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

Joh*_*hat 8 ruby ruby-on-rails

注意这最初是作为一个关于404错误的问题开始的,但现在问题是为什么我应用的补丁会产生影响.

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

例如,如果你启动一个空的rails项目,添加一个Product model和controller,设置你​​的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
Run Code Online (Sandbox Code Playgroud)

第一次点击页面时,它会按预期返回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
Run Code Online (Sandbox Code Playgroud)

第二个反应显然是错误的.

以下是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]
Run Code Online (Sandbox Code Playgroud)

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

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

我在这做错了什么?

编辑

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

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

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

编辑#2 我试图跟踪Rails代码库中发生更改的时间,以确定它是否是故意的.似乎这个看似无害的提交是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
Run Code Online (Sandbox Code Playgroud)

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

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

Gre*_*ell 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;
}
Run Code Online (Sandbox Code Playgroud)

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