Reloading controller plugins on each request

Hey guys. I'm writing an "acts_as_X" plugin that's used by controllers. Unfortunately, the plugin isn't being reloaded for each request [in the dev env].

I thought that adding     config.reload_plugins = true if RAILS_ENV == 'development' to environment.rb , as well as     require 'acts_as_X' to my plugin's init.rb would do the trick, but it doesn't.

Is there a way to configure Rails to reload the plugin for each request?

Here's the code: http://gist.github.com/361804

Thanks! Nick

Did you try require_dependency instead of require?

> Is there a way to configure Rails to reload the plugin for each request?

> Here's the code:http://gist.github.com/361804

> Thanks! > Nick

Did you try require_dependency instead of require?

I've never heard of require_dependency. I just gave it a try, but unfortunately, all requests but the first result in this error:

"A copy of ActsAsDashboard::ClassMethods has been removed from the module tree but is still active!"

That behaviour also occurs when I put this in environment.rb:

ActiveSupport::Dependencies.explicitly_unloadable_constants << 'ActsAsDashboard'

The answer's dead easy. Those child modules and classes need to split out into separate files. So ActsAsDashboard::Config must be in lib/ acts_as_dashboard/config.rb , ActsAsDashboard::ClassMethods must be in lib/acts_as_dashboard/class_methods.rb , etc.

Once I did that, everything in the plugin was reloaded.

Just for your enlightenment, a big part of the problem is that you were including your module in ActionController::Base. This was problematic because the rails framework (including ActionController::Base) doesn't get reloaded, but you were forcing Rails to reload your module event though ActionController::Base was still hanging onto it (you wouldn't have had this issue if you'd included it in ApplicationController. Using require rather than require_dependency sidesteps Rails' dependency stuff (which is the thing that manages code reloading)

Fred

Hey Frederick. Thanks for the tip. That makes sense. It turns out that I didn't completely solve the problem of the plugin reloading, and I think what you described is the culprit.

For some reason, ActsAsDashboard::ClassMethods is not being reloaded for each request.

I tried your suggestion of changing the plugin's init.rb from this:     require 'acts_as_dashboard'     ActionController::Base.send :include, ActsAsDashboard to this:     require 'acts_as_dashboard'     ApplicationController.send :include, ActsAsDashboard

However, every request other than the first results in this error:     "undefined local variable or method `acts_as_dashboard' for DashboardsController:Class" citing line 2 of app/controllers/dashboards_controller.rb :     1 class DashboardsController < ApplicationController     2 acts_as_dashboard

Might you know what needs to be done to get Rails to reload ActsAsDashboard::ClassMethods for each request?

Thanks, mate! Nick

Hey Frederick. Thanks for the tip. That makes sense. It turns out that I didn't completely solve the problem of the plugin reloading, and I think what you described is the culprit.

For some reason, ActsAsDashboard::ClassMethods is not being reloaded for each request.

I tried your suggestion of changing the plugin's init.rb from this: require 'acts_as_dashboard' ActionController::Base.send :include, ActsAsDashboard to this: require 'acts_as_dashboard' ApplicationController.send :include, ActsAsDashboard

However, every request other than the first results in this error: "undefined local variable or method `acts_as_dashboard' for DashboardsController:Class" citing line 2 of app/controllers/dashboards_controller.rb : 1 class DashboardsController < ApplicationController 2 acts_as_dashboard

Might you know what needs to be done to get Rails to reload ActsAsDashboard::ClassMethods for each request?

Thanks, mate! Nick

Whoops, I sent that last email a bit prematurely. After switching to using

ApplicationController.send :include, ActsAsDashboard

in init.rb , this error:

undefined local variable or method `acts_as_dashboard' for DashboardsController:Class"

was occuring on subsequent requests because init.rb is only run when the web server is started; it isn't run before any web requests.

So on the first request, ActsAsDashboard has been loaded, and life's peachy. But on the 2nd request, all of those non-Rails framework classes (such as ApplicationController, DashboardsController, etc) are unloaded and then loaded. However, because my init.rb isn't executed, ActsAsDashboard isn't included into ApplicationController. Thus, #acts_as_dashboard isn't available to DashboardsController, and the error above occurs.

I've found that putting     include ActsAsDashboard into DashboardsController gets rid of the error above, and results in ActsAsDashboard::ClassMethods being reloaded for each request. However, that's only a short-term solution.

Does anyone know what the proper fix is for this?

Thanks again, Nick

However, every request other than the first results in this error: "undefined local variable or method `acts_as_dashboard' for DashboardsController:Class" citing line 2 of app/controllers/dashboards_controller.rb : 1 class DashboardsController < ApplicationController 2 acts_as_dashboard

Might you know what needs to be done to get Rails to reload ActsAsDashboard::ClassMethods for each request?

If you want something to be reloadable you should use require_dependency to load it. The main thing though is that a plugin's init.rb is not re-run between requests, so the include you do on ApplicationController is lost after the first request.

Fred

Right. So how can one get a module included in a controller on subsequent requests without explicitly putting an #include in the controller?

To facilitate development (IE: not restart WEBrick between requests), I have this at the moment:     class DashboardsController < ApplicationController       include ActsAsDashboard       acts_as_dashboard

I'd like to figure out how to remove that #include . Any ideas?

I suppose you could define self.inherited on ActionController::Base and do your setup from there.

Fred