如何防止我的初始化配置在开发模式下丢失? [英] How can I keep my initializer configuration from being lost in development mode?
问题描述
我正在开发一个使用引擎的 Rails 应用.我正在使用初始化程序来配置我的引擎控制器之一,以便它会触发主机应用程序中的操作.代码如下所示:
I'm working on a Rails app that uses an engine. I'm using an initializer to configure one of my engine's controllers so that it will trigger an action in the host app. The code looks something like this:
# config/initializers/my_engine.rb
MyEngine::SomeController.after_filter proc {
# Do something in the host app
}, :only => :update
这在生产中运行良好,但在开发模式下,仅在第一个请求时调用 proc.这是因为类正在重新加载并且此配置丢失,因为它存储在类变量中.(例如,MyEngine::SomeController
是从它所在的文件重新加载的,并且由于 after_filter
未在那里声明,因此不会重新添加.)
This works fine in production, but in development mode, the proc is only called on the first request. This is because the classes are getting reloaded and this configuration is lost, because it was stored in a class variable. (For example, MyEngine::SomeController
is reloaded from the file it's in, and since the after_filter
isn't declared there, it isn't added back on.)
在开发模式下,Rails 使用以下加载策略:
In development mode, Rails uses the following load strategy:
app
目录中的代码在每次请求时都会重新加载,前提是您正在积极更改它.lib
目录中的代码以及config/initializer
文件在应用程序启动时加载一次.
- Code in the
app
directory is reloaded on each request, on the assumption that you're actively changing it. - Code in the
lib
directory, along withconfig/initializer
files, are loaded once, when the application boots.
初始化文件一般用于配置gem.过去,gems 的代码大多在 lib
目录中,因此运行一次它们的配置就足够了.
Initializer files are generally used for configuring gems. In the past, gems have mostly had code in the lib
directory, so running their configuration once was sufficient.
然而,Rails 引擎在 app
目录中有代码:控制器、模型等.这些文件在开发模式下根据每个请求重新加载.因此,我上面例子中的配置丢失了.
However, Rails engines have code in the app
directory: controllers, models, etc. These files are reloaded in development mode on each request. Therefore, configuration like my example above is lost.
Rails 提供了 config.to_prepare
专门用来解决这个问题:它在生产中运行一次,在开发中的每个请求上运行一次.
Rails provides config.to_prepare
specifically to solve this problem: it run once in production, and on every request in development.
例如,我们在 application.rb 中有这个,它工作正常:
For example, we have this in application.rb, which works fine:
config.to_prepare do
# set up class variables (after_filters, etc)
end
然而,如果我必须将所有引擎的配置都放在 application.rb
中,这将失去 config/initializers
保持组织有序的意义.
However, if I have to put all my engines' configuration in application.rb
, this defeats the point of config/initializers
in keeping things organized.
因此,对于我引擎的 app
目录中的任何类配置,我想将该代码放在 config/initializers
下的文件中.
So, for any configuration of classes in my engines' app
directories, I want to put that code in files under config/initializers
.
这是我的问题.
- 我不清楚如何在初始化文件中将
config
纳入范围.我想应该是Rails.application.config
.是吗? - 我可以添加多个
to_prepare
块吗?恐怕多次调用它会覆盖以前的块.
- I'm unclear how to get
config
into scope in an initializer file. I'm thinking it would beRails.application.config
. Is that right? - Can I add add multiple
to_prepare
blocks? I'm afraid that calling it multiple times will overwrite previous blocks.
正如@Frederick Cheung 提到的,Rails.application.config.to_prepare
确实在 config/initializer
文件中工作,并且可以根据需要在各种文件;每次调用都会将其块附加到一个数组中,因此不会覆盖任何内容.
As @Frederick Cheung mentioned, Rails.application.config.to_prepare
does work in config/initializer
files, and one can use as many of these as needed in the various files; each call appends its block to an array, so nothing is overwritten.
所以这个问题的解决方案是:
# 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
块在开发模式下在 每个请求 上被调用,但它似乎每第三个请求随机调用一次或者.我添加了块:
One thing that still seems odd: I expected the to_prepare
block to be called on every request in development mode, but instead it seems to be called randomly every 3rd request or so. I added block:
Rails.application.config.to_prepare do
Rails.logger.info "Running the prepare block!"
end
... 重新启动了我的应用程序,并刷新了页面九次.我只看到第 1、5、7 和 9 次请求的消息.我不确定是什么解释了这种行为,但它确实解释了为什么我的代码没有 to_prepare
在开发中间歇性地工作.
... restarted my app, and refreshed the page nine times. I only saw the message on the 1st, 5th, 7th and 9th requests. I'm not sure what explains this behavior, but it does explain why my code without the to_prepare
worked intermittently in development.
推荐答案
您可以根据需要添加任意数量的 to_prepare
块 - 当您执行 config.to_prepare
时,Rails正在做(在 railties 的 configuration.rb
中)
You can add as many to_prepare
blocks as you want - when you do config.to_prepare
, Rails is doing (in configuration.rb
in railties)
def to_prepare(&blk)
to_prepare_blocks << blk if blk
end
然后迭代这些块,将它们交给ActionDispatch::Reloader
,其中to_prepare
是使用ActiveSupport::Callbacks
实现的(即用于 before_save
等的相同内容).多个 to_prepare
块就可以了.
and then iterates over those blocks handing them over to ActionDispatch::Reloader
, where to_prepare
is implemented using ActiveSupport::Callbacks
(i.e. the same thing that is used for before_save
and so on). Multiple to_prepare
blocks are fine.
目前看起来 Rails 在读取应用程序初始化器后会遍历 to_prepare_blocks
,因此添加到 Rails.application.configuration.to_prepare
应该可以工作.您可能更喜欢使用 ActionDispatch::Reloader.to_prepare
.
Currently it looks like Rails iterates over to_prepare_blocks
after reading application initialisers so adding to Rails.application.configuration.to_prepare
should work. You may prefer to use ActionDispatch::Reloader.to_prepare
.
这篇关于如何防止我的初始化配置在开发模式下丢失?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!