我对rails如何实现before_filter
等过滤器感兴趣。
但在阅读完源代码后,我仍然感到困惑。
我注意到rails'框架维护filter_chain
,并在目标方法之前运行过滤器。
但是,我不明白一个重要的过程:rails如何捕获一个方法调用?
我的意思是,例如,我有一个班级Dog
,并为方法树皮设置before_filter
。
当我调用dog.bark
时,rails应该以某种方式捕获此调用,并改为运行其修改后的方法。
但是,我在源代码中找不到这样的代码。
任何人都可以告诉我这个想法或指出代码所在的位置吗?
答案 0 :(得分:22)
当您设置before_filter
或任何类似的过滤器(想想after_filter
,around_filter
)时,您正在使用{{3}进行设置}或Symbol,lambda或块。
before_filter :bark
before_filter Proc.new { |k| k.bark }
上面通过调用Proc将符号或块附加到堆栈here。这构建了您所指的“链”。
此“链”中的每个项目都是set_callback
类的实例。这堂课知道
:bark
方法” Dog
类) Callback
个实例会附加到ActiveSupport::Callbacks::Callback
中的ActiveSupport::Callbacks::CallbackChain
。
初始化每个Callback
类时,运行__update_callbacks
以将过滤器从Symbol
,Proc
,lambda或块规范化为通用的可调用格式。
最后,当CallbackChain
运行时,它会在每个Callback
实例上调用_compile_filter
,并在此时调用 过滤器实际执行在适当的背景下。
重要的是要指出你不创建像
这样的过滤器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以在适当时间执行的'指令'。
首先,铁路如何知道我已经召集过: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
您可以看到start
如何做到这一点。
这确实是一个糟糕的例子,因为你可以(而且应该)直接从eat
调用bark
,但这应该得到重点。
答案 1 :(得分:1)
Rails不会按照您描述的方式捕获方法调用。如果查看AbstractController::Base.process
,它将查找要为调度操作调用的方法,运行过滤器然后调用实际方法。换句话说,您的控制器方法不是直接调用,而是通过此process
方法调用。