controller是如何利用ActiveSupport::Callbacks的
检查下controller的before_action是怎样定义的
[8] pry(main)> StudentsController.method(:before_action).source_location
=> ["/home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/actionpack-5.1.2/lib/abstract_controller/callbacks.rb", 165]
源码如下,可见便利方法有12个,以before为例,有before_action、prepend_before_action、skip_before_action、append_before_action(同before_action)
而这些before_action、after_action等所定义的callback,其实都是围绕process_action的
module AbstractController
module Callbacks
extend ActiveSupport::Concern
include ActiveSupport::Callbacks
included do
define_callbacks :process_action,
terminator: ->(controller, result_lambda) { result_lambda.call if result_lambda.is_a?(Proc); controller.performed? },
skip_after_callbacks_if_terminated: true
end
def process_action(*args)
run_callbacks(:process_action) do
super
end
end
module ClassMethods
[:before, :after, :around].each do |callback|
define_method "#{callback}_action" do |*names, &blk|
_insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, callback, name, options)
end
end
define_method "prepend_#{callback}_action" do |*names, &blk|
_insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, callback, name, options.merge(prepend: true))
end
end
# Skip a before, after or around callback. See _insert_callbacks
# for details on the allowed parameters.
define_method "skip_#{callback}_action" do |*names|
_insert_callbacks(names) do |name, options|
skip_callback(:process_action, callback, name, options)
end
end
# *_action is the same as append_*_action
alias_method :"append_#{callback}_action", :"#{callback}_action"
end
end
end
end