Rails:environment.rb中所需的lib文件中定义的过滤器从生产环境中的filter_chain中消失。 为什么?

发布于 2024-07-14 06:01:28 字数 1702 浏览 3 评论 0 原文

在我的 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淤浪 2024-07-21 06:01:28

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 加载之后、应用程序控制器之前影响它。

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

Frederick Cheung on the Rails list had the answer:

Because cache_classes does a little more than just that. The way
before filters work, if Foo < Bar then only those filters defined in
Bar at that point will be inherited by Foo - adding them to Bar at a
later date will not do anythingn

In development mode, the app starts, your file is required, the filter
added to ActionController::Base. Later the first request comes along,
the controller is loaded and it inherits that filter.

When cache_classes is true then all of your application classes are
loaded ahead of time. This happens before your file is required, so
all of your controllers already exist when that file is run and so it
has no effect. You could solve this by requiring this file from an
initializer (ensuring it runs before app classes are loaded), but
really why wouldn;t you just put this in application.rb ?

Fred


My real case was actually way more involved, and this is the way I found to solve the issue:

config.after_initialize do
  require 'foobar'
end

The after_initialize block runs after the framework has been initialized but before it loads the application files, hence, it'll affect ActionPack::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.

疑心病 2024-07-21 06:01:28

将 ruby​​ 脚本放入

RAILS_ROOT\config\初始化程序

包含

require "foobar.rb"

This 为我调用 before_filter 。

Drop a ruby script in

RAILS_ROOT\config\initializers

that contains

require "foobar.rb"

This invokes the before_filter for me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文