跳至內容 跳至搜尋
方法
D
R
S

執行個體公開方法

define_callbacks(*names)

定義物件生命週期中支援呼叫回事件的集合。

define_callbacks :validate
define_callbacks :initialize, :save, :destroy
選項
  • :terminator - 決定一個 before 篩選器何時會暫停呼叫回鍊,防止之後的 before 和 around 呼叫回被呼叫,以及事件被觸發。這應該是一個要執行的 lambda。目前物件和呼叫回的結果 lambda 會提供給 terminator lambda。

    define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false }
    

    在此範例中,如果任何 before validate 呼叫回傳回 false,任何後續的 before 和 around 呼叫回都不會被執行。

    預設 terminator 會在呼叫回擲回 :abort 時暫停鍊。

  • :skip_after_callbacks_if_terminated - 決定 after 呼叫回是否應該由 :terminator 選項終止。預設上 after 呼叫回會執行,無關於呼叫回鍊是否被終止。如果 :terminator 選項設為 nil,這個選項無效。

  • :scope - 指示物件用於呼叫回時應該執行哪些方法。

    class Audit
      def before(caller)
        puts 'Audit: before is called'
      end
    
      def before_save(caller)
        puts 'Audit: before_save is called'
      end
    end
    
    class Account
      include ActiveSupport::Callbacks
    
      define_callbacks :save
      set_callback :save, :before, Audit.new
    
      def save
        run_callbacks :save do
          puts 'save in main'
        end
      end
    end
    

    在上述範例中,當你儲存帳號時,方法 Audit#before 會被呼叫。另一方面

    define_callbacks :save, scope: [:kind, :name]
    

    將會觸發 Audit#before_save。這是透過呼叫指定執行個體的 #{kind}_#{name} 建構的。在此範例中,「kind」為「before」而「name」為「save」。在此脈絡中,:kind:name 有特殊含義::kind 指呼叫回種類(before/after/around),而 :name 指呼叫回被定義於其上的方法。

    如下聲明

    define_callbacks :save, scope: [:name]
    

    將會呼叫 Audit#save

注意事項

傳遞給 define_callbacksnames 不能以 !?= 結尾。

多次呼叫具有相同 namesdefine_callbacks 會覆寫先前使用 set_callback 註冊的呼叫回。

# File activesupport/lib/active_support/callbacks.rb, line 900
        def define_callbacks(*names)
          options = names.extract_options!

          names.each do |name|
            name = name.to_sym

            ([self] + self.descendants).each do |target|
              target.set_callbacks name, CallbackChain.new(name, options)
            end

            module_eval <<-RUBY, __FILE__, __LINE__ + 1
              def _run_#{name}_callbacks(&block)
                run_callbacks #{name.inspect}, &block
              end

              def self._#{name}_callbacks
                get_callbacks(#{name.inspect})
              end

              def self._#{name}_callbacks=(value)
                set_callbacks(#{name.inspect}, value)
              end

              def _#{name}_callbacks
                __callbacks[#{name.inspect}]
              end
            RUBY
          end
        end

reset_callbacks(name)

移除指定事件的所有已設定呼叫回。

# File activesupport/lib/active_support/callbacks.rb, line 810
def reset_callbacks(name)
  callbacks = get_callbacks name

  self.descendants.each do |target|
    chain = target.get_callbacks(name).dup
    callbacks.each { |c| chain.delete(c) }
    target.set_callbacks name, chain
  end

  set_callbacks(name, callbacks.dup.clear)
end

set_callback(name, *filter_list, &block)

安裝指定事件的呼叫回。

set_callback :save, :before, :before_method
set_callback :save, :after,  :after_method, if: :condition
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }

第二個參數表示呼叫回應該在事件 :before:after:around 時執行。如果省略,則假設為 :before。這表示上述第一個範例也可以撰寫成

set_callback :save, :before_method

呼叫回可以指定為命名執行個體方法的符號;作為程序、lambda 或區塊;或作為對應到 define_callbacks:scope 參數所決定的特定方法做出回應的物件。

如果給定一個程序、lambda 或區塊,其主體會在目前物件的脈絡中評量。它也可以選擇性地接受目前物件作為參數。

Before 和 around 呼叫回會按設定順序進行呼叫;after 呼叫回會按相反順序進行呼叫。

周圍的回呼函式可以在事件的傳回值,如果事件沒有被停止的話,從 yield 的呼叫存取。

選項
  • :if - 符號或符號陣列,每個符號命名一個執行個方法或例程;只有在所有符號都傳回 true 值時,才會呼叫回呼函式。

    如果給定例程,則在目前物件的內容中評估其主體。它也可以選擇將目前物件接受為引數。

  • :unless - 符號或符號陣列,每個符號命名一個執行個方法或例程;只有在所有符號都傳回 false 值時,才會呼叫回呼函式。

    如果給定例程,則在目前物件的內容中評估其主體。它也可以選擇將目前物件接受為引數。

  • :prepend - 如果為 true,會將回呼函式加入到現有的鏈中,而不是附加在後面。

# File activesupport/lib/active_support/callbacks.rb, line 736
def set_callback(name, *filter_list, &block)
  type, filters, options = normalize_callback_params(filter_list, block)

  self_chain = get_callbacks name
  mapped = filters.map do |filter|
    Callback.build(self_chain, filter, type, options)
  end

  __update_callbacks(name) do |target, chain|
    options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
    target.set_callbacks name, chain
  end
end

skip_callback(name, *filter_list, &block)

略過先前設定的回呼函式。如同 set_callback,可以傳入 :if:unless 選項,以控制略過回呼函式時機。

注意:此範例使用 PersonRecord#saving_message;您可以在 此處 看到其定義。

class Writer < PersonRecord
  attr_accessor :age
  skip_callback :save, :before, :saving_message, if: -> { age > 18 }
end

當 if 選項傳回 true 時,會略過回呼函式。

writer = Writer.new
writer.age = 20
writer.save

輸出

- save
saved

當 if 選項傳回 false 時,不會略過回呼函式。

young_writer = Writer.new
young_writer.age = 17
young_writer.save

輸出

saving...
- save
saved

如果回呼函式尚未設定(除非 :raise 選項設為 false),將引發 ArgumentError

# File activesupport/lib/active_support/callbacks.rb, line 785
def skip_callback(name, *filter_list, &block)
  type, filters, options = normalize_callback_params(filter_list, block)

  options[:raise] = true unless options.key?(:raise)

  __update_callbacks(name) do |target, chain|
    filters.each do |filter|
      callback = chain.find { |c| c.matches?(type, filter) }

      if !callback && options[:raise]
        raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined"
      end

      if callback && (options.key?(:if) || options.key?(:unless))
        new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless])
        chain.insert(chain.index(callback), new_callback)
      end

      chain.delete(callback)
    end
    target.set_callbacks name, chain
  end
end