在开发模式下的每个请求上重新加载*文件后,如何挂钩到Rails *?

时间:2011-09-21 18:26:54

标签: ruby-on-rails-3

我正在使用gem根据用户配置选项动态设置ActiveRecord模型(例如table_name)的属性。

我有一个实现此目的的初始化程序。然而,我的问题是在开发模式下,这些类被重新加载,因此它们不会保持这些值的设置。

所以我想我会使用一个铁路来挂钩重新加载这些文件并在模型上再次运行我的配置。然而,我的问题是,铁路中的config.to_prepare似乎在reload!实际发生之前运行。我可以通过一些记录来证明这一点:

module MyMod
  class Railtie < Rails::Railtie

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

如果我加载我的控制台,我会得到第一个日志:

Contact object_id: 2202692040

如果我检查Contact.object_id它匹配:

Contact.object_id  #=> 2202692040

然后我reload!

reload!

我的to_prepare日志中的Rails记录器:

Contact object_id: 2202692040

所以它仍然有旧的object_id,但是当我在控制台中检查它时:

Contact.object_id  #=> 2197355080

哪个是新加载的类对象id。

那么在重新加载文件后如何让to_prepare运行?使用Rails 3.0.10

更新

我也尝试将此操作手动附加到after_prepare上的ActionDispatch::Callbacks回调,如下所示:

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

它确实在config.to_prepare之后运行回调,但它似乎仍然发生before重新加载文件...我得到与上面相同的行为。

2 个答案:

答案 0 :(得分:16)

编写一个初始化程序,如果cache_classesfalse,则使用ActionDispatch::Reloader设置运行gem安装例程的to_prepare回调。

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

它在带有reload!方法的控制台和Rack应用程序服务器中都可以正常工作。

答案 1 :(得分:0)

我相信Rails重新加载器只会解开常量。在应用程序中引用常量时,模型会重新加载自动加载。

在你的回调中,我认为你必须通过引用所有模型来手动触发负载。也许你的宝石可以保留包含它的所有模型的列表,然后只需引用常量来自动加载它们......

model_names.each { |model_name| model_name.constantize }

您可以使用self.included构建列表:

module MyGem
  self.included(base)
    @model_names ||= Set.new
    @model_names += base.to_s
  end
end