我正在使用一个使用引擎的Rails应用程序。我正在使用初始化程序来配置我的引擎的一个控制器,以便它在主机应用程序中触发一个动作。代码看起来像这样:
# config/initializers/my_engine.rb
MyEngine::SomeController.after_filter proc {
# Do something in the host app
}, :only => :update
这在生产中工作正常,但在开发模式下,只在第一个请求时调用proc。这是因为类被重新加载并且此配置丢失,因为它存储在类变量中。 (例如,MyEngine::SomeController
从其所在的文件重新加载,并且由于after_filter
未在此处声明,因此不会重新添加。{/ p>
在开发模式下,Rails使用以下加载策略:
app
目录中的代码会重新加载。lib
目录中的代码以及config/initializer
文件将加载。初始化文件通常用于配置gems。在过去,gems主要在lib
目录中有代码,因此运行一次配置就足够了。
但是,Rails引擎在app
目录中有代码:控制器,模型等。这些文件在每个请求的开发模式下重新加载。因此,上面的示例配置将丢失。
Rails专门提供config.to_prepare
来解决这个问题:它在生产中运行一次,在开发中的每个请求上运行。
例如,我们在application.rb中有这个,它工作正常:
config.to_prepare do
# set up class variables (after_filters, etc)
end
但是,如果我必须将所有引擎的配置都放在application.rb
中,那么config/initializers
就会使事情变得井然有序。
因此,对于我的引擎'app
目录中的任何类配置,我想将该代码放在config/initializers
下的文件中。
以下是我的问题。
config
放入初始化文件的范围内。我想它会是Rails.application.config
。是吗?to_prepare
块吗?我担心多次调用它会覆盖以前的块。正如@Frederick Cheung所说,Rails.application.config.to_prepare
在config/initializer
文件中有效,并且可以根据需要在各种文件中使用尽可能多的文件;每个调用将其块附加到数组,因此不会覆盖任何内容。
此问题的解决方案是:
# config/initializers/my_engine.rb
Rails.application.config.to_prepare do
MyEngine::SomeController.after_filter proc {
# Do something in the host app
}, :only => :update
end
有一点似乎仍然很奇怪:我希望在开发模式下在每个请求上调用to_prepare
块,但是它似乎每隔3个请求随机调用一次。我添加了块:
Rails.application.config.to_prepare do
Rails.logger.info "Running the prepare block!"
end
...重新启动了我的应用,并刷新了九次页面。我只在第1次,第5次,第7次和第9次请求中看到了该消息。我不确定是什么解释了这种行为,但它确实解释了为什么我的代码没有 to_prepare
在开发过程中间歇性地工作。
答案 0 :(得分:10)
您可以根据需要添加任意数量的to_prepare
块 - 当您执行config.to_prepare
时,Rails正在执行(在configuration.rb
的铁路中)
def to_prepare(&blk)
to_prepare_blocks << blk if blk
end
然后迭代这些块,将它们交给ActionDispatch::Reloader
,其中to_prepare
使用ActiveSupport::Callbacks
实现(即用于before_save
的相同内容,依此类推)。多个to_prepare
块很好。
目前看起来Rails在阅读应用程序初始化程序后会迭代to_prepare_blocks
,因此添加到Rails.application.configuration.to_prepare
应该可行。您可能更喜欢使用ActionDispatch::Reloader.to_prepare
。
答案 1 :(得分:1)
没有什么可以阻止你在app / models中的文件中执行初始化代码。
例如
class MyClass
def self.run_me_when_the_class_is_loaded
end
end
MyClass.run_me_when_the_class_is_loaded
MyClass.run_me ...将在加载类时运行....这就是我们想要的,对吧?
不确定它是否是Rails方式....但它非常简单,并且不依赖于Rails的转变。