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