当您设置before_filter 或任何类似的过滤器(想想after_filter、around_filter),您可以使用Symbol 或Proc, lambda 或块。
before_filter :bark
before_filter Proc.new { |k| k.bark }
上面通过调用set_callback 将符号或块附加到堆栈here。这构建了您所指的“链”。
这个“链”中的每个项目都是ActiveSupport::Callbacks::Callback 类的一个实例。这个类知道
- 方法(符号)或它必须运行的块(即你的类的
:bark方法)
- 它必须在 中运行的上下文(即您的
Dog 类)
Callback 实例附加到__update_callbacks 中的ActiveSupport::Callbacks::CallbackChain。
当每个 Callback 类被初始化时,_compile_filter 运行以将过滤器从 Symbol、Proc、lambda 或块标准化为通用的可调用格式。
最后,当CallbackChain 运行时,它将在每个Callback 实例上调用start,并且此时过滤器实际上是在适当的上下文中执行的。
请务必指出,您将不会创建类似
的过滤器
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 是如何做到这一点的。
这确实是一个不好的例子,因为您可以(而且应该)直接从bark 调用eat,但这应该能说明问题。