views:

538

answers:

2

I'm writing a Rails plugin (lets call it Foo). I want it to provide 'bar' class function in controllers, so that I can do:

class ApplicationController
  bar ...
end

bar is defined from withing the plugin loading file vendor/plugins/foo/init.rb. Something like

class ActionController::Base
  def self.bar
    ...
  end
end

The problem is that some other plugins (in my case ResourceController) might load before foo and access ApplicationController.

So what happens is that ApplicationController is loaded before the plugin 'foo' and fails since there is no 'bar' defined YET.

So ... how do I properly make it work works?

I noticed that many other plugins that extend ActionController (for example inherited_resources, resource_controller, ) are doing exactly the same, so it seems its a matter of who loads first to decide if it fails or works.

I know that I can put code in some module and manually add the module to ApplicationController code before calling 'foo'. I'd rather not, I like the cleanliness of just 'foo'.

I also don't want to do a manual 'require'. Plugins are supposed to be auto-loaded all by themselves :)

A: 

From what I understand,

ResourceController loads before plugin foo and tries to use the bar method you have defined in foo. Usually, gems and plugins are loaded before application classes. (Take a look at rails/railties/lib/initializer.rb). Could you provide a stack-trace of the error so that one can debug this.

Also, for extending the classes, this seems a better alternative to me:

module ActionController
  class Base
     class << self
       ... # Class methods here
     end
  ... # Instance methods here
  end
end
Swanand
not really. ResourceController references ApplicationController which references foo. but "bar" is not YET loaded since plugin "foo" loads AFTER ResourceController
Vitaly Kushner
+1  A: 

What you have is a classic plugin load order problem. Ryan Daigle had a nice article on this back in 2007. I'll sum up the recommendation here:

# in RAILS_ROOT/config/environment.rb:
...
Rails::Initializer.run do |config|
  # load Bar before Foo, then everything else:
  config.plugins = [ :bar, :foo, :all ]
  ...
end
James A. Rosen