Nat*_*ong 19 ruby-on-rails ruby-on-rails-3.1
我正在使用一个使用引擎的Rails应用程序.我正在使用初始化程序来配置我的引擎的一个控制器,以便它在主机应用程序中触发一个动作.代码看起来像这样:
# config/initializers/my_engine.rb
MyEngine::SomeController.after_filter proc {
# Do something in the host app
}, :only => :update
Run Code Online (Sandbox Code Playgroud)
这在生产中工作正常,但在开发模式下,proc仅在第一个请求时调用.这是因为类被重新加载并且此配置丢失,因为它存储在类变量中.(例如,MyEngine::SomeController从它所在的文件重新加载,并且由于after_filter未在那里声明,因此不会重新加载它.)
在开发模式下,Rails使用以下加载策略:
app如果您正在主动更改目录,则会在每个请求上重新加载目录中的代码.lib目录中的代码以及config/initializer文件将加载一次.初始化程序文件通常用于配置gem.在过去,gems主要在lib目录中有代码,因此运行一次配置就足够了.
但是,Rails引擎在app目录中有代码:控制器,模型等.这些文件在每个请求的开发模式下重新加载.因此,上面的示例配置丢失了.
Rails config.to_prepare专门解决了这个问题:它在生产中运行一次,在开发中的每个请求上运行一次.
例如,我们在application.rb中有这个,它工作正常:
config.to_prepare do
# set up class variables (after_filters, etc)
end
Run Code Online (Sandbox Code Playgroud)
但是,如果我必须将所有引擎的配置都放入其中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
Run Code Online (Sandbox Code Playgroud)
有一点似乎仍然很奇怪:我希望在开发模式下的每个请求to_prepare上调用块,但是它似乎每隔3个请求随机调用一次.我添加了块:
Rails.application.config.to_prepare do
Rails.logger.info "Running the prepare block!"
end
Run Code Online (Sandbox Code Playgroud)
...重新启动我的应用程序,并刷新页面九次.我只在第1次,第5次,第7次和第9次请求中看到了该消息.我不知道如何解释这种行为,但它解释了为什么我的代码没有在to_prepare开发间歇工作.
Fre*_*ung 10
您可以根据需要添加任意数量的to_prepare块 - 当您这样做时config.to_prepare,Rails正在执行(configuration.rb在铁路中)
def to_prepare(&blk)
to_prepare_blocks << blk if blk
end
Run Code Online (Sandbox Code Playgroud)
然后迭代那些将它们交给的块ActionDispatch::Reloader,在那里to_prepare使用ActiveSupport::Callbacks(即使用的相同的东西,before_save等等).多个to_prepare块都没问题.
目前看起来Rails to_prepare_blocks在阅读应用程序初始化程序后会迭代,因此添加Rails.application.configuration.to_prepare应该可以工作.您可能更喜欢使用ActionDispatch::Reloader.to_prepare.