views:

84

answers:

3

Hello, I need some help with virtual attributes. This code works fine but how do I use it inside a plugin. The goal is to add this methods to all classes that uses the plugin.

class Article < ActiveRecord::Base

  attr_accessor :title, :permalink

  def title
    if @title 
      @title
    elsif self.page
      self.page.title
    else 
      ""
    end
  end

  def permalink
    if @permalink
      @permalink
    elsif self.page
      self.page.permalink
    else
      ""
    end
  end
end

Thanks

A: 

It appears that you want a Module for this

# my_methods.rb 
module MyMethods
  def my_method_a
    "Hello"
  end
end

The you want to include it into the classes you want to use it for.

class MyClass < ActiveRecord::Base
  include MyMethods
end

> m = MyClass.new
> m.my_method_a
=> "Hello!"

Take a look here for more information on mixing in modules. You can put the module wherever in a plugin if you like, just ensure its named correctly so Rails can find it.

Peer Allan
A: 

Create a module structure like YourPlugin::InstanceMethods and include it this module like this:

module YourPlugin
  module InstanceMethods
    # your methods
  end
end

ActiveRecord::Base.__send__(:include, YourPlugin::InstanceMethods)

You have to use __send__ to make your code Ruby 1.9 compatible. The __send__ line is usually placed at the init.rb file on your plugin root directory.

Nando Vieira
+1  A: 

You can run the plugin generator to get started.

script/generate plugin acts_as_page

You can then add a module which defines acts_as_page and extends it into all models.

# in plugins/acts_as_page/lib/acts_as_page.rb
module ActsAsPage
  def acts_as_page
    # ...
  end
end

# in plugins/acts_as_page/init.rb
class ActiveRecord::Base
  extend ActsAsPage
end

This way the acts_as_page method is available as a class method to all models and you can define any behavior into there. You could do something like this...

module ActsAsPage
  def acts_as_page
    attr_writer :title, :permalink
    include Behavior
  end

  module Behavior
    def title
      # ...
    end

    def permalink
      # ...
    end
  end
end

And then when you call acts_as_page in the model...

class Article < ActiveRecord::Base
  acts_as_page
end

It will define the attributes and add the methods. If you need things to be a bit more dynamic (such as if you want the acts_as_page method to take arguments which changes the behavior) try out the solution I present in this Railscasts episode.

ryanb
Thanks for your answer but I get this error: active_record/base.rb:1959:in `method_missing': private method `attr_writer' called for ActiveRecord::Base:Class (NoMethodError)Let me try to be more specific:I want to be able to add this to my model: acts_as_pageEvery model that uses this plugin should get two virtual attributes (title and permalink) which is used to create or update a page model in the before_save callback inside the plugin. Everything works fine but I don't get the title and permalink values.I would paste the code but I'm running out of characters :)
Ola Karlsson
I updated the answer to better fit your requirements. I had forgotten attr_writer was private, but that shouldn't be a problem with this new solution.
ryanb
Thank you very much! I forgot that I needed to extend my module into ActiveRecord.
Ola Karlsson