Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails3 gem: acts_as_something

I'm trying to extract some common code into a gem.

I'm thinking that acts_as_somethingis a good strategy for simple re-use.

Is there a good tutorial that discusses this for rails3 gems? I've found several that discuss rails2 (such as http://guides.rubyonrails.org/plugins.html) but that is specific to rails2

here are some of the tutorials/blogs I've already read:

  • http://guides.rubyonrails.org/plugins.html
  • http://www.thoughtsincomputation.com/categories/coding-gems-for-rails-3-tutorials (this is an excellent start but doesn't cover the act_as_* issue or controllers)

thanks

like image 230
cbrulak Avatar asked Oct 25 '10 20:10

cbrulak


1 Answers

UPDATE: I've added a blog post based on this answer, but with much more detail: http://thoughtsincomputation.com/posts/coding-an-acts_as-gem-for-rails-3

--

I'm not aware of another tutorial source off the top of my head, but here are some general tips.

Rails 3 makes use of a really useful feature called Railtie - see http://api.rubyonrails.org/classes/Rails/Railtie.html .

So, if I were implementing an acts_as_* gem, I'd start there. My railtie might look something like:

# lib/acts_as_awesome/railtie.rb
require 'rails'
require 'acts_as_awesome'

module ActsAsAwesome
  class Railtie < Rails::Railtie
    config.to_prepare do
      ApplicationController.send(:extend, ActsAsAwesome::Hook)
    end
  end
end

and the ActsAsAwesome::Hook code:

# lib/acts_as_awesome/hook.rb
module ActsAsAwesome::Hook
  def acts_as_awesome(*args)
    options = args.extract_options!
    # do the things that make the controller awesome.
    include ActsAsAwesome::InstanceMethods
    before_filter :an_awesome_filter
  end
end

I feel the concepts here are sound and have used similar processes before. Basically, it would tell Rails to execute the to_prepare block once during production and before each request in development (we want that because ApplicationController will be reloaded at those times, potentially wiping out our hook method); and the hook is just that: it adds a hook to all controllers (or rather, all controllers that extend ApplicationController) to allow the user to introduce the real "Awesome" code into their controllers without otherwise affecting controllers that don't need it.

The #acts_as_awesome hook doesn't, in itself, convey the Awesome functionality. That's because not all controllers might need this functionality. Instead, the method is responsible for introducing the real awesome stuff, via the ActsAsAwesome::InstanceMethods module. This way, the user only gets the Awesome functionality if they explicitly call the acts_as_awesome method. It also adds a before filter to the controller to demonstrate that the code in this method would be evaluated exactly the same as if it were in the target controller class itself.

This technique should work exactly the same if you're targeting models instead of controllers: just inject your hook into ActiveRecord::Base. As AR:B is only loaded at Rails boot, you should probably be able to put that into an initializer (refer to the Railtie docs), but I reserve the right to be mistaken here.

A gotcha concerning the railtie: the documentation reads as if it should have been autodetected, but I often have problems with this. To get around it, simply require the railtie from your gem's main source file (in the above example, that would be lib/acts_as_awesome.rb).

You can see the entire ActsAsAwesome source in all its glory at my github account: http://github.com/sinisterchipmunk/acts_as_awesome

I hope this is helpful. Your question was somewhat high-level so a high-level response is the best I can do.

-Colin MacKenzie IV

http://thoughtsincomputation.com

@sinisterchipmnk

like image 69
sinisterchipmunk Avatar answered Nov 10 '22 19:11

sinisterchipmunk