Skip to content
This repository
tree: d42d97d2e3
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 199 lines (176 sloc) 8.288 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
module AbstractController
  module Callbacks
    extend ActiveSupport::Concern

    # Uses ActiveSupport::Callbacks as the base functionality. For
    # more details on the whole callback system, read the documentation
    # for ActiveSupport::Callbacks.
    include ActiveSupport::Callbacks

    included do
      define_callbacks :process_action, :terminator => "response_body"
    end

    # Override AbstractController::Base's process_action to run the
    # process_action callbacks around the normal behavior.
    def process_action(*args)
      run_callbacks(:process_action, action_name) do
        super
      end
    end

    module ClassMethods
      # If :only or :except are used, convert the options into the
      # primitive form (:per_key) used by ActiveSupport::Callbacks.
      # The basic idea is that :only => :index gets converted to
      # :if => proc {|c| c.action_name == "index" }, but that the
      # proc is only evaluated once per action for the lifetime of
      # a Rails process.
      #
      # ==== Options
      # * <tt>only</tt> - The callback should be run only for this action
      # * <tt>except</tt> - The callback should be run for all actions except this action
      def _normalize_callback_options(options)
        if only = options[:only]
          only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ")
          options[:per_key] = {:if => only}
        end
        if except = options[:except]
          except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ")
          options[:per_key] = {:unless => except}
        end
      end

      # Skip before, after, and around filters matching any of the names
      #
      # ==== Parameters
      # * <tt>names</tt> - A list of valid names that could be used for
      # callbacks. Note that skipping uses Ruby equality, so it's
      # impossible to skip a callback defined using an anonymous proc
      # using #skip_filter
      def skip_filter(*names, &blk)
        skip_before_filter(*names)
        skip_after_filter(*names)
        skip_around_filter(*names)
      end

      # Take callback names and an optional callback proc, normalize them,
      # then call the block with each callback. This allows us to abstract
      # the normalization across several methods that use it.
      #
      # ==== Parameters
      # * <tt>callbacks</tt> - An array of callbacks, with an optional
      # options hash as the last parameter.
      # * <tt>block</tt> - A proc that should be added to the callbacks.
      #
      # ==== Block Parameters
      # * <tt>name</tt> - The callback to be added
      # * <tt>options</tt> - A hash of options to be used when adding the callback
      def _insert_callbacks(callbacks, block)
        options = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
        _normalize_callback_options(options)
        callbacks.push(block) if block
        callbacks.each do |callback|
          yield callback, options
        end
      end

      ##
      # :method: before_filter
      #
      # :call-seq: before_filter(names, block)
      #
      # Append a before filter. See _insert_callbacks for parameter details.

      ##
      # :method: prepend_before_filter
      #
      # :call-seq: prepend_before_filter(names, block)
      #
      # Prepend a before filter. See _insert_callbacks for parameter details.

      ##
      # :method: skip_before_filter
      #
      # :call-seq: skip_before_filter(names, block)
      #
      # Skip a before filter. See _insert_callbacks for parameter details.

      ##
      # :method: append_before_filter
      #
      # :call-seq: append_before_filter(names, block)
      #
      # Append a before filter. See _insert_callbacks for parameter details.

      ##
      # :method: after_filter
      #
      # :call-seq: after_filter(names, block)
      #
      # Append an after filter. See _insert_callbacks for parameter details.

      ##
      # :method: prepend_after_filter
      #
      # :call-seq: prepend_after_filter(names, block)
      #
      # Prepend an after filter. See _insert_callbacks for parameter details.

      ##
      # :method: skip_after_filter
      #
      # :call-seq: skip_after_filter(names, block)
      #
      # Skip an after filter. See _insert_callbacks for parameter details.

      ##
      # :method: append_after_filter
      #
      # :call-seq: append_after_filter(names, block)
      #
      # Append an after filter. See _insert_callbacks for parameter details.

      ##
      # :method: around_filter
      #
      # :call-seq: around_filter(names, block)
      #
      # Append an around filter. See _insert_callbacks for parameter details.

      ##
      # :method: prepend_around_filter
      #
      # :call-seq: prepend_around_filter(names, block)
      #
      # Prepend an around filter. See _insert_callbacks for parameter details.

      ##
      # :method: skip_around_filter
      #
      # :call-seq: skip_around_filter(names, block)
      #
      # Skip an around filter. See _insert_callbacks for parameter details.

      ##
      # :method: append_around_filter
      #
      # :call-seq: append_around_filter(names, block)
      #
      # Append an around filter. See _insert_callbacks for parameter details.

      # set up before_filter, prepend_before_filter, skip_before_filter, etc.
      # for each of before, after, and around.
      [:before, :after, :around].each do |filter|
        class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
# Append a before, after or around filter. See _insert_callbacks
# for details on the allowed parameters.
def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} # options[:if] = (Array.wrap(options[:if]) << "!halted") if false
set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before, name, options)
end # end
end # end

# Prepend a before, after or around filter. See _insert_callbacks
# for details on the allowed parameters.
def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} # options[:if] = (Array.wrap(options[:if]) << "!halted") if false
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
end # end
end # end

# Skip a before, after or around filter. See _insert_callbacks
# for details on the allowed parameters.
def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options)
end # end
end # end

# *_filter is the same as append_*_filter
alias_method :append_#{filter}_filter, :#{filter}_filter # alias_method :append_before_filter, :before_filter
RUBY_EVAL
      end
    end
  end
end
Something went wrong with that request. Please try again.