【问题标题】:Setting more than one cookie in integration test causes NoMethodError after upgrading rails 2.3升级 rails 2.3 后在集成测试中设置多个 cookie 会导致 NoMethodError
【发布时间】:2012-05-16 06:20:05
【问题描述】:

这一切在 Rails 2.3.5 中运行良好,但是当承包商公司直接升级到 2.3.14 时,突然所有集成测试都在说:

NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]

我的 ApplicationController 上有一个 before_filter,它设置了一堆 cookie 供一些 javascript 使用,我发现如果我注释掉除设置 cookie 值的行之外的所有行,它可以正常工作,但它不会不管我留在哪一行。

before_filter :set_cookies

def set_cookies
  cookies['logged_in'] = (logged_in ? 'y' : 'n')
  cookies['gets_premium'] = (gets_premium ? 'y' : 'n')
  cookies['is_admin'] = (is_admin ? 'y' : 'n')
end

如果这些行中只有一条处于活动状态,则在集成测试中一切正常,否则我会收到上述错误。例如,考虑以下测试/响应:

test "foo" do
  get '/'
end


$ ruby -I"lib:test" test/integration/foo_test.rb -n test_foo -v
Loaded suite test/integration/foo_test
Started
test_foo(FooTest): E

Finished in 5.112648 seconds.

  1) Error:
test_foo(FooTest):
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
    test/integration/foo_test.rb:269:in `test_foo'

1 tests, 0 assertions, 0 failures, 1 errors

但如果其中任何两个 cookie 设置行被注释掉,我会得到:

$ ruby -I"lib:test" test/integration/foo_test.rb -n test_foo -v
Loaded suite test/integration/foo_test
Started
test_foo(FooTest): .

Finished in 1.780388 seconds.

1 tests, 0 assertions, 0 failures, 0 errors

在开发和生产模式下运行的网站运行良好 - 这只是让测试通过的问题。此外,通过调试输出,我已验证错误不会在设置 cookie 的方法中引发,一切正常执行,错误发生在稍后的某个地方(但回溯并没有告诉我在哪里)

【问题讨论】:

    标签: ruby-on-rails cookies integration-testing ruby-on-rails-2


    【解决方案1】:

    这是 rack rack 如何将 cookie 与会话 cookie 一起写入客户端的一个错误。 Rack 包含双换行符并省略了分号。

    firefox 等浏览器可以处理格式不正确的 cookie 数据,但集成测试客户端不能。

    为了解决这个问题,我必须在发送给客户端之前重写 cookie 标头。

    在 environment.rb 中:

    require 'rack_rails_cookie_header_hack'
    

    在 lib/rack_rails_cookie_header_hack.rb 中:

    class RackRailsCookieHeaderHack
    
      def initialize(app)
        @app = app
      end
    
      def call(env)
        status, headers, body = @app.call(env)
        if headers['Set-Cookie']
          cookies = headers['Set-Cookie']
          cookies = cookies.split("\n") if is_str = cookies.is_a?(String)
          if cookies.respond_to?(:collect!)
            cookies.collect! { |h| h.strip }
            cookies.delete_if { |h| h.empty? }
            cookies.collect! { |h| h.include?(';') ? h : h + ';' }
          end
          headers['Set-Cookie'] = is_str ? cookies.join("\n").strip : cookies
        end
        [status, headers, body]
      end
    end
    

    对不起,来源没有明确说明,我实际上在不久前修复了这个问题并遇到了这个问题,并认为我会发布我的补丁。

    【讨论】:

      【解决方案2】:

      L0ne 的答案对我有用,但您还需要包含它 - 它可以放在 lib/rack_rails_cookie_header_hack.rb 的底部,前提是您需要它位于 environment.rb 文件的底部 - 即在 Rails 之后::初始化程序已运行:

      ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, RackRailsCookieHeaderHack)
      

      【讨论】:

      • 谢谢,我错过了那部分。具体来说,我包括: config.after_initialize do ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, RackRailsCookieHeaderHack) end
      【解决方案3】:

      被遗忘的旧问题...

      我没有测试过 Lone 的修复方法,但他已经正确地发现了问题。如果你捕捉到异常并使用exception.backtrace 打印,你会发现问题是由 gems/actionpack/lib/action_controller/integration.rb:329

      有问题的代码是这样的:

      cookies.each do |cookie|
        name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
        @cookies[name] = value
      end
      

      如果你和我一样,只对一些超快速的集成测试感兴趣,而不太关心未来的可维护性(因为它是 rails 2),那么你可以在其中添加一个条件过滤器方法

      cookies.each do |cookie|
        unless cookie.blank?
          name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
          @cookies[name] = value
        end
      end
      

      问题解决了

      【讨论】:

        猜你喜欢
        • 2016-03-06
        • 2012-12-09
        • 1970-01-01
        • 1970-01-01
        • 2022-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多