检查下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