Rails控制器过滤器在移除后神奇地重新出现

时间:2015-02-24 16:19:45

标签: ruby-on-rails ruby ruby-on-rails-3 actioncontroller before-filter

我看到非常奇怪的行为,其中是否运行过滤器似乎取决于它是否设置为在第一个规范中运行以使用该控制器。

所以我把它减少到一个最小的控制器:

class WtfController < ActionController::Base
  before_filter :raise_error

  def index
    render nothing: true, status: 200
  end

  private
  def raise_error
    raise OMGError
  end
end

(OMGError只是StandardError的子类)

一个测试用例:

describe 'wtfspec' do
  it 'with filter' do
    expect do
      controller = set_up_controller
      controller.process(:index)
    end.to raise_error
  end

  it 'without filter' do
    expect do
      controller = set_up_controller
      controller.class.skip_filter :raise_error
      controller.process(:index)
    end.not_to raise_error
  end
end

def set_up_controller
  controller = WtfController.new
  controller.request = ActionController::TestRequest.new
  controller.response = ActionController::TestResponse.new
  controller
end

在第二次测试中应该跳过过滤器,但它不是。

如果未运行第一个expect块,则第二个测试通过。只有当第二次失败时才运行它。同样,如果我在第一次测试中skip_filter并使用before_filter为第二次测试读取它,那么第二次测试就无法运行过滤器。

这就是事情 - 如果我在controller.class._process_action_callbacks.map(&:filters)行之前的规范(第二次测试)中检查WtfController上设置的过滤器列表(使用controller.process),那么它确实已成功删除,skip_filter行正常工作。但如果我在控制器中检查它(在raise_error中),它似乎已经以某种方式被读取了!

注意&#39; readded&#39;,而不是&#39;:实际运行的raise_error回调的object_id与原始回调(运行之前的那个)不同skip_filter)。但是过滤器数组的object_id(实际上是ActiveSupport::Callbacks::CallbackChain)与控制器一样保持不变。

(编辑:结果是所有的回调对象都有不同的object_ids,而不仅仅是被移除的。神秘加深......)

无论两个测试中的每一个都是新的控制器对象还是重用相同的控制器对象(因为过滤器是WtfController类对象的属性),行为是相同的,不是实例)。

我花了一天时间调试这个并且完全神秘化了。有任何见解赞赏。 Rails版本是3.2.21。谢谢:))

1 个答案:

答案 0 :(得分:0)

在测试不同的rails版本后,这种行为在4.0中不会发生。因此可能是导轨中的一个错误,现在已经修复了。可能与activesupport中的this commit相关。