【问题标题】:How do I hook into Rails *after* files are reloaded on each request in development mode?在开发模式下,每个请求都重新加载文件后,我如何挂钩 Rails *after* 文件?
【发布时间】:2019-02-01 10:28:51
【问题描述】:

我正在开发一个 gem,它根据用户配置选项动态设置 ActiveRecord 模型(例如 table_name)的属性。

我有一个可以实现这一点的初始化程序。然而,我的问题是,在开发模式下,这些类会重新加载,因此它们不会维护这些值集。

所以我想我会使用 railtie 连接到重新加载这些文件的位置,并在模型上再次运行我的配置。然而,我的问题是 railtie 中的 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

更新

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

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 文件已重新加载...我得到与上述相同的行为。

【问题讨论】:

标签: ruby-on-rails-3


【解决方案1】:

编写一个初始化程序,如果 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 应用服务器中工作。

【讨论】:

  • 似乎to_prepare is called once 当类也被缓存时,所以你可以这样做: { ActionDispatch::Reloader.to_prepare do FooBar.install!结束}
  • 初始化程序对我不起作用,但我删除了它并且它起作用了,很难在文档中找到这样的东西,谢谢
  • 对于新的 Rails 5.x 版本,我们需要使用ActiveSupport::Reloader.to_prepare 而不是ActionDispatch::Reloader.to_prepare
  • 对于新的 Rails 6.x 版本,我们现在必须使用 Rails.application.reloader.to_prepare 而不是 ActiveSupport::Reloader.to_prepare
【解决方案2】:

我相信 Rails 重新加载器只会解开常量。当在您的应用中引用常量时,模型会通过自动加载重新加载。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    相关资源
    最近更新 更多