[X,Y,Z] .each {| m |的区别是什么?包括m}并包括X,Y,Z?

时间:2009-04-20 22:51:03

标签: ruby-on-rails ruby

注意这最初是关于404错误的问题,但现在问题是我应用的补丁会产生什么影响。

如何获得缓存操作以在所有引发ActiveRecord :: RecordNotFound异常的请求上返回404,而不仅仅是第一个请求?

例如,如果你启动一个空的rails项目,添加一个产品模型和控制器,设置你的database.yml,在production.rb中设置你的缓存后端,rake db:migrate,然后开始生产并点击网站一个不存在的对象,例如http://localhost:3000/product/show/1234

class ProductController < ApplicationController

  caches_action :show

  def show
    @product = Product.find(params[:id])
    render :text => "asdf"
  end

end

第一次点击页面时,它会按预期返回404页面。但是,对该URL的每次后续匹配都会返回一个200 OK的空白页面。你如何让它每次都返回404?

以下是CURL请求,后跟日志

~ $ curl -I http://0.0.0.0:3000/product/show/1234
HTTP/1.1 404 Not Found
Connection: close
Date: Mon, 20 Apr 2009 22:49:18 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Content-Length: 14097

~ $ curl -I http://0.0.0.0:3000/product/show/1234
HTTP/1.1 200 OK
Connection: close
Date: Mon, 20 Apr 2009 22:49:19 GMT
X-Runtime: 6
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Content-Length: 0

第二种反应显然是错误的。

以下是2个请求的日志副本:

Processing ProductController#show (for 127.0.0.1 at 2009-04-20 17:35:24) [GET]
  Parameters: {"id"=>"1234"}

ActiveRecord::RecordNotFound (Couldn't find Product with ID=1234):
  app/controllers/product_controller.rb:6:in `show'

Rendering rescues/layout (not_found)


Processing ProductController#show (for 127.0.0.1 at 2009-04-20 17:35:30) [GET]
  Parameters: {"id"=>"1234"}
Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x23e36d4 @options={:cache_path=>nil, :store_options=>{}, :layout=>nil}>] rendered_or_redirected.
Filter chain halted as [#<ActionController::Filters::AroundFilter:0x23e3580 @kind=:filter, @options={:unless=>nil, :if=>nil, :only=>#<Set: {"show"}>}, @method=#<ActionController::Caching::Actions::ActionCacheFilter:0x23e36d4 @options={:cache_path=>nil, :store_options=>{}, :layout=>nil}>, @identifier=nil>] did_not_yield.
Completed in 12ms (View: 0, DB: 0) | 200 OK [http://0.0.0.0/product/show/1234]

实际上,如果你将缓存的操作从缓存中拉出来,那里就会有一些空的垃圾。

cache.fetch("views/0.0.0.0:3000/product/show/1234")
=> ["", nil, [], []]

我在这里做错了什么?

修改

我已经确认Rails 2.1.2和2.2.2没有表现出这种行为,但2.3.2确实如此。 (即旧版本不会将空响应存储到缓存中,并且确实会为后续请求抛出404)

我在测试边缘Rails时遇到问题,因为在启动服务器时加载它会导致以下错误: foob​​ar / vendor / rails / activesupport / lib / active_support / dependencies.rb:440:in`load_missing_constant':uninitialized constant ActionController :: Failsafe(NameError)

我已经对2-3稳定分支375e8976e3的当前负责人进行了测试,它也表现出这种行为。

编辑#2 我试图跟踪Rails代码库中发生更改的时间,以确定它是否是故意的。似乎this seemingly innocuous commit是bug开始的地方。

以下是二分的细节,其中404表示期望的行为,200表示不期望的行为。

2-3-stable branch
    375e8976e3 - 200
    b1c989f28d - 200
    beca1f2e15 - 200
    f1fff0a48  - 200
    f1e20ce9a7 - 200
    a5004573d8 - 200
    2e1132fad8 - 200 - the difference seems to start at this commit
    c69d8c043f - 404
    d961592886 - 404
    276ec16007 - 404
    0efec6452  - 404
    13c6c3cfc5 - 404
    fb2325e35  - 404

2-2 stable
    3cb89257b4 - 404

这是一个反转更改的补丁,当应用于标记v2.3.2.1,即dc88847e5ce392eed210b97525c14fca55852867时,修复了问题。然而,我不够聪明,不知道为什么这个看似微不足道的变化实际上会有所作为! 也许比我聪明的人可以对这种情况有所了解?

diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 0facf70..0790807 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -1403,12 +1403,9 @@ module ActionController #:nodoc:
   end

   Base.class_eval do
-    [ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
-      Cookies, Caching, Verification, Streaming, SessionManagement,
-      HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods,
-      RecordIdentifier, RequestForgeryProtection, Translation
-    ].each do |mod|
-      include mod
-    end
+    include Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers
+    include Cookies, Caching, Verification, Streaming, SessionManagement
+    include HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods
+    include RecordIdentifier, RequestForgeryProtection, Translation
   end
 end

编辑#3 补丁似乎也修复了上面显示的相关错误,其中“已完成的XYms(DB:Z)| 404未找到[http://0.0.0.0/product/1234]”未显示在日志中。

编辑#4 上面的补丁破坏了ActionPack中的其他内容,因此我深入研究并生成了一个不会导致附带损害的问题。补丁和任何后续更新都将在the rails lighthouse

1 个答案:

答案 0 :(得分:16)

include(X, Y, Z)实际上的运作顺序与include X; include Y; include Z不同。

下面我粘贴了在Ruby 1.8.6中实现Module#include方法的C代码。

static VALUE
rb_mod_include(argc, argv, module)
    int argc;
    VALUE *argv;
    VALUE module;
{
    int i;

    for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
    while (argc--) {
      rb_funcall(argv[argc], rb_intern("append_features"), 1, module);
      rb_funcall(argv[argc], rb_intern("included"), 1, module);
    }
    return module;
}

即使你不熟悉Ruby的C内部,很明显这个函数有一个for循环向上迭代来检查所有参数的类型是否为T_MODULE,然后使用while循环迭代向下实际包含模块 - 因此include(X, Y, Z)中的模块实际上将包含在Z, Y, X的顺序中。我还没有浏览过所有相关的Rails模块,但我想有一些依赖于顺序的东西,一旦切换包含顺序就会失败。