当您设置 abefore_filter或任何类似的过滤器(想想after_filter, around_filter)时,您可以使用Symbol或Proc、 lambda 或块。
before_filter :bark
before_filter Proc.new { |k| k.bark }
上面通过调用将符号或块附加到此处set_callback的堆栈中。这构建了您所指的“链”。
此“链”中的每个项目都是该类的一个实例ActiveSupport::Callbacks::Callback。这个班知道
- 它必须运行的方法(符号)或块(即您的类的
:bark方法)
- 它必须在其中运行的上下文(即您的
Dog班级)
Callback实例附加到ActiveSupport::Callbacks::CallbackChainin 。__update_callbacks
当每个Callback类初始化时,_compile_filter运行以将过滤器从Symbol、Proc、 lambda 或块标准化为通用的可调用格式。
最后,当CallbackChain运行时,它将调用start每个Callback实例,此时过滤器实际上是在适当的上下文中执行的。
重要的是要指出您不会创建像这样的过滤器
before_filter dog.bark
这将执行dog.bark并将其返回值传递before_filter给附加到CallbackChain. 目的是将某种指令传递before_filter给 Rails 以便稍后为您执行。你会改为做类似的事情
before_filter Proc.new { d = Dog.new; d.bark }
中的代码Proc未执行。当上面的行由 Rails 运行时。相反,Rails 被告知Proc将CallbackChain. 这Proc是您传递给 Rails 以在适当的时间执行的“指令”。
首先,rails 是如何知道我打过电话的:bark
至于这个,假设你的Dog类被简单地定义为
class Dog
def bark
end
def eat
end
end
(虽然这是一个可怕的例子),你可能想要有类似的东西
before_bark :eat
这需要您定义bark回调,然后告诉您的bark方法运行相关的bark回调。
class Dog
extend ActiveModel::Callbacks
define_callbacks :bark
before_bark :eat
def bark
run_callbacks(:bark) { YOUR BARK CODE HERE }
end
def eat
end
end
你可以看看这是怎么ActiveRecord::Callbacks做到的。
这确实是一个不好的例子,因为您可以(并且应该)eat直接从 调用bark,但这应该明白这一点。