0

在我的 rails 应用程序中,我在 lib 中有一个文件,除其他外,它设置了一个在所有控制器上运行的过滤器。

在开发环境下运行时,一切正常。但是,在生产过程中,过滤器丢失了。有趣的是,通过检查filter_chain,我注意到其他过滤器仍然存在,例如。那些在插件中定义的,或者稍后在特定控制器类中定义的。

我已经用 rails edge 和 v2.3.0 对此进行了测试。

测试更新:

我现在已经用旧的导轨进行了测试,发现问题出现在 v2.1.0 中,但在 v2.0.5 中没有,我将它们一分为二,发现986aec5导轨是有罪的。


我已将行为隔离到以下小测试用例:

# 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

如果 中的production.rbconfig.cache_classes更改truefalse,则测试应用程序正常工作。

我仍然想知道为什么类重新加载会导致这样的事情。

4

2 回答 2

3

Rails 名单上的 Frederick Cheung给出了答案

因为 cache_classes 不仅如此。过滤器工作之前的方式,如果 Foo < Bar 则只有那些在 Bar 中定义的过滤器将被 Foo 继承 - 稍后将它们添加到 Bar 不会做任何事情

在开发模式下,应用程序启动,您的文件是必需的,过滤器添加到 ActionController::Base。稍后第一个请求出现,控制器被加载并继承该过滤器。

当 cache_classes 为 true 时,所有应用程序类都会提前加载。这发生在需要您的文件之前,因此在运行该文件时您的所有控制器都已经存在,因此没有任何效果。您可以通过从初始化程序中要求此文件来解决此问题(确保它在加载应用程序类之前运行),但实际上为什么不把它放在 application.rb 中?

弗雷德


我的真实案例实际上涉及更多,这就是我发现解决问题的方法:

config.after_initialize do
  require 'foobar'
end

after_initialize块在框架初始化之后但在加载应用程序文件之前运行,因此,它会ActionPack::Base在加载之后但在应用程序控制器之前生效。

我想这是处理生产中进行的所有预加载的一般安全方法。

于 2009-03-06T21:58:22.533 回答
0

将 ruby​​ 脚本放入

RAILS_ROOT\config\initializers

包含

require "foobar.rb"

这为我调用了 before_filter。

于 2009-03-06T21:58:45.013 回答