Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I hook into Rails *after* files are reloaded on each request in development mode?

I'm working on a gem that sets properties on ActiveRecord models (such as table_name) dynamically based on a user config option.

I have an initializer that achieves this. My problem however is that in dev mode, these classes are reloaded, so they don't maintain these values set.

So I thought I'd use a railtie to hook into the point where these files are reloaded and run my config again on the models. My problem however is that config.to_prepare in the railtie appears to run before the reload! actually takes place. I can prove this with a bit of logging:

module MyMod
  class Railtie < Rails::Railtie

    config.to_prepare do
      Rails.logger.debug("Contact object_id: #{Contact.object_id}")
    end
  end
end

if I load up my console, I get the first log:

Contact object_id: 2202692040

If I check Contact.object_id it matches up:

Contact.object_id  #=> 2202692040

Then I reload!

reload!

Rails logger from my to_prepare logs:

Contact object_id: 2202692040

So it still has the old object_id, but when I check it in the console:

Contact.object_id  #=> 2197355080

Which is the newly loaded class object id.

So how do I get to_prepare to run after the files are reloaded? Using Rails 3.0.10

update

I've also tried manually attaching this action to the after_prepare callback on the ActionDispatch::Callbacks like so:

initializer "apartment.init" do
  ActionDispatch::Callbacks.set_callback(:prepare, :after) do
    Rails.logger.debug("Contact object_id: #{Contact.object_id}")
  end
end

It does indeed run the callback after the config.to_prepare but it still appears to happen before the files are reloaded... I get the same behaviour as above.

like image 326
brad Avatar asked Sep 21 '11 18:09

brad


1 Answers

Write an initializer that, if cache_classes is false, uses ActionDispatch::Reloader to set a to_prepare callback that runs your gem's installation routine.

initializer 'foobar.install' do
  if Rails.configuration.cache_classes
    FooBar.install!
  else
    ActionDispatch::Reloader.to_prepare do
      FooBar.install!
    end
  end
end

It'll work both in the console with the reload! method and in the Rack application server.

like image 198
vjt Avatar answered Sep 20 '22 08:09

vjt