在我的 Rails 应用程序中,我在 lib 中有一个文件,其中除其他外,还设置了一个在所有控制器上运行的过滤器。
在开发环境下运行时一切正常。 然而,在生产过程中,过滤器丢失了。 有趣的是,通过检查 filter_chain
,我注意到其他过滤器仍然存在,例如。 那些在插件中定义的,或者稍后在特定控制器类中定义的。
我已经用 Rails Edge 和 v2.3.0 对此进行了测试。
测试更新:
我现在已经使用较旧的 Rails 进行了测试,发现问题出现在 v2.1.0 中,但在 v2.0.5 中没有,我将它们一分为二并找到了 986aec5 Rails 承诺有罪。
我已将行为隔离到以下小型测试用例:
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
render :text => 'not filtered'
end
end
# lib/foobar.rb
ActionController::Base.class_eval do
before_filter :foobar
def foobar
render :text => 'hi from foobar filter'
end
end
# config/environment.rb (at end of file)
require 'foobar'
这是在开发环境下运行时得到的输出:
$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter
这是生产环境的输出:
$ script/server -e production &
$ curl localhost:3000/foo
> not filtered
正如所提到的与之前相比,当我通过插件执行相同的操作时,它适用于任何环境。 我需要的只是将 lib/foobar.rb
下的内容放入插件的 init.rb
文件中。
因此,在某种程度上,我已经有了解决方法,但我想了解发生了什么以及导致过滤器在生产过程中丢失的原因。
我猜想这是 Rails 在不同环境中处理加载的不同方式,但我需要更深入地研究。
更新
确实,我现在已将其范围缩小到以下配置行:
config.cache_classes = false
如果在 生产.rb
中,config.cache_classes
已从 true
更改> 为 false
,测试应用程序正常工作。
我仍然想知道为什么类重新加载会导致这样的事情。
In my rails application, I have a file in lib that, among other things, sets up a filter that runs on all controllers.
When running under development environment, everything runs fine. However, under production the filter goes missing. Funny thing is, by inspecting the filter_chain
, I noticed other filters remain, eg. those defined in plugins, or later in the specific controller class.
I've tested this with both rails edge and v2.3.0.
Testing update:
I've now tested with older rails and found the issue to be present back to v2.1.0, but not in v2.0.5, I've bisect them and found the 986aec5 rails commit to be guilty.
I've isolated the behavior to the following tiny test case:
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
render :text => 'not filtered'
end
end
# lib/foobar.rb
ActionController::Base.class_eval do
before_filter :foobar
def foobar
render :text => 'hi from foobar filter'
end
end
# config/environment.rb (at end of file)
require 'foobar'
Here's the output I get when running under the development environment:
$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter
And here's the output for the production environment:
$ script/server -e production &
$ curl localhost:3000/foo
> not filtered
As alluded to before, it works fine for any environment when I do the same thing via plugin. All I need is to put what's under lib/foobar.rb
in the plugin's init.rb
file.
So in a way I already have a workaround, but I'd like to understand what's going on and what's causing the filter to go missing when in production.
I conjecture it's something in the different ways Rails handles loading in the different environments, but I need to dig deeper.
update
Indeed, I've now narrowed it down to the following config line:
config.cache_classes = false
If, in production.rb
, config.cache_classes
is changed from true
to false
, the test application works properly.
I still wonder why class reloading is causing such thing.
发布评论
评论(2)
Rails 列表中的 Frederick Cheung 曾答案:
我的真实案例实际上涉及更多,这就是我发现解决问题的方法:
after_initialize 块在框架初始化之后但在加载应用程序文件之前运行,因此,它会在
ActionPack::Base
加载之后、应用程序控制器之前影响它。我想这是处理生产中进行的所有预加载的通常安全的方法。
Frederick Cheung on the Rails list had the answer:
My real case was actually way more involved, and this is the way I found to solve the issue:
The
after_initialize
block runs after the framework has been initialized but before it loads the application files, hence, it'll affectActionPack::Base
after it's been loaded, but before the application controllers are.I guess that's the generally safe way to deal with all the preloading that goes on in production.
将 ruby 脚本放入
包含
This 为我调用 before_filter 。
Drop a ruby script in
that contains
This invokes the before_filter for me.