Active Support 回调
回调是在对象生命周期中的关键点运行的代码钩子。典型的用例是让一个基类定义一组与它提供的其他功能相关的回调,以便子类可以安装增强或修改基类功能的回调,而无需覆盖或重新定义基类的方法。
混合此模块允许您定义对象生命周期中将支持回调的事件(通过 ClassMethods#define_callbacks
),设置要调用的实例方法、proc 或回调对象(通过 ClassMethods#set_callback
),并在适当的时间运行已安装的回调(通过 run_callbacks
)。
默认情况下,回调通过抛出 :abort
来中止。有关详细信息,请参见 ClassMethods#define_callbacks
。
支持三种类型的回调:before 回调,在某个事件之前运行;after 回调,在事件之后运行;around 回调,包围事件的块,在它们产生时触发事件。回调代码可以包含在实例方法、proc 或 lambda 中,也可以包含在响应特定预定方法的回调对象中。有关详细信息,请参见 ClassMethods#set_callback
。
class Record
include ActiveSupport::Callbacks
define_callbacks :save
def save
run_callbacks :save do
puts "- save"
end
end
end
class PersonRecord < Record
set_callback :save, :before, :saving_message
def saving_message
puts "saving..."
end
set_callback :save, :after do |object|
puts "saved"
end
end
person = PersonRecord.new
person.save
输出
saving...
- save
saved
命名空间
- 模块 ActiveSupport::Callbacks::CallTemplate
- 模块 ActiveSupport::Callbacks::ClassMethods
- 模块 ActiveSupport::Callbacks::Conditionals
- 模块 ActiveSupport::Callbacks::Filters
方法
常量
CALLBACK_FILTER_TYPES | = | [:before, :after, :around].freeze |
实例公共方法
run_callbacks(kind, type = nil) 链接
运行给定事件的回调。
按设置顺序调用 before 和 around 回调,生成块(如果有),然后以相反顺序运行 after 回调。
如果回调链被中止,则返回 false
。否则返回块的结果,如果未设置回调,则返回 nil
,如果设置了回调但未给出块,则返回 true
。
run_callbacks :save do
save
end
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/callbacks.rb, line 96 def run_callbacks(kind, type = nil) callbacks = __callbacks[kind.to_sym] if callbacks.empty? yield if block_given? else env = Filters::Environment.new(self, false, nil) next_sequence = callbacks.compile(type) # Common case: no 'around' callbacks defined if next_sequence.final? next_sequence.invoke_before(env) env.value = !env.halted && (!block_given? || yield) next_sequence.invoke_after(env) env.value else invoke_sequence = Proc.new do skipped = nil while true current = next_sequence current.invoke_before(env) if current.final? env.value = !env.halted && (!block_given? || yield) elsif current.skip?(env) (skipped ||= []) << current next_sequence = next_sequence.nested next else next_sequence = next_sequence.nested begin target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) target.send(method, *arguments, &block) ensure next_sequence = current end end current.invoke_after(env) skipped.pop.invoke_after(env) while skipped&.first break env.value end end invoke_sequence.call end end end