在其他人之后运行Rails控制器before_action回调

时间:2017-01-09 22:35:34

标签: ruby-on-rails ruby

是否有一种简单的方法可以附加到rails中的控制器的before_action列表,以便稍后添加的其他before_action回调将在我的回调之前而不是之后运行?

我的用处是我担心其他控制器会包含,并且我希望包含它的控制器能够添加他们自己的before_action方法,但是在所有这些方法之后调用我的一个方法,但仍然在实际行动之前。

由于它是一群与开发人员相当大的代码库,为了实用性,我不希望这个问题的每个用户都必须prepend_before_action或必须记住{{1我的模块在声明了它们的回调之后而不是在类的顶部。

我很确定没有内置的方法可以做到这一点,而且我对ruby中的元编程并不是很熟悉。但是,当回调正在运行时,是否有某种方法可以挂钩回调列表的内部,并在末尾添加新的回调或什么?

1 个答案:

答案 0 :(得分:0)

我发现了一个非常简单的解决方案 - 查看ActiveSupport::Callbacks源代码,我注意到CallbackChain#append_one方法是将before_action回调添加到链中,每次添加时都调用remove_duplicates方法回调。所以我可以在我的模块中执行以下操作,覆盖before_action方法:

module MyModule
  extend ActiveSupport::Concern

  included do
    before_action :my_last_callback
  end

  class_methods do
    def before_action(*args, &blk)
      method(:before_action).super_method.call(*args, &blk)
      method(:before_action).super_method.call(:my_last_callback)
    end
  end

  def my_last_callback
    # do stuff after all before_action callbacks
  end
end

现在,子类可以根据需要添加尽可能多的before_action回调,并且它们将保持其顺序,但my_last_callback始终会被调用。 (回调链中现在会有额外的插入/删除,现在回调数量可能是O(n ^ 2)而不是O(n),但我不认为有足够的回调来使这个回调问题)。