1

这一切在 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 的方法中抛出,一切正常,错误发生在稍后的某个地方(但回溯没有告诉我在哪里)

4

3 回答 3

2

事实证明,这是 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

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

于 2012-06-21T23:02:22.423 回答
2

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

ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, RackRailsCookieHeaderHack)
于 2012-07-03T13:14:18.620 回答
0

被遗忘的老问题...

我还没有测试过 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

问题解决了

于 2013-09-05T17:41:24.490 回答