如何防止我的初始化配置在开发模式下丢失? [英] How can I keep my initializer configuration from being lost in development mode?

查看:47
本文介绍了如何防止我的初始化配置在开发模式下丢失?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个使用引擎的 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 with config/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 be Rails.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆