Spec-Zone.ru › Ruby on Rails 8.1

module ActiveSupport::Callbacks::ClassMethods

Открытые методы экземпляра

define_callbacks (*names) Показать исходный код
# File activesupport/lib/active_support/callbacks.rb, line 903
        def define_callbacks(*names)
          options = names.extract_options!

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

            module_eval <<-RUBY, __FILE__, __LINE__ + 1
              def _run_#{name}_callbacks
                yield if block_given?
              end
              silence_redefinition_of_method(:_run_#{name}_callbacks)

              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

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

Определяет наборы событий в жизненном цикле объекта, для которых поддерживаются колбэки.

define_callbacks :validate
define_callbacks :initialize, :save, :destroy
Параметры
  • :terminator — определяет, когда фильтр before останавливает цепочку колбэков, не позволяя вызывать последующие колбэки before и around и запускать событие. Здесь должна быть лямбда, которая будет выполнена. Текущий объект и результат лямбды колбэка передаются лямбде-терминатору.

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

    В этом примере, если любой колбэк before validate возвращает false, последующие колбэки before и around не выполняются.

    Терминатор по умолчанию останавливает цепочку, когда колбэк вызывает :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.

Примечания

names, передаваемый в define_callbacks, не должен оканчиваться на !, ? или =.

Повторный вызов define_callbacks с тем же names перезапишет ранее зарегистрированные с помощью set_callback колбэки.

reset_callbacks (name) Показать исходный код
# File activesupport/lib/active_support/callbacks.rb, line 813
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) Показать исходный код
# File activesupport/lib/active_support/callbacks.rb, line 739
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

Устанавливает колбэк для указанного события.

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

Колбэк можно задать как символ, указывающий на метод экземпляра; как proc, лямбду или блок; либо как объект, который отвечает на определённый метод, указанный аргументом :scope метода define_callbacks.

Если задан proc, лямбда или блок, его тело выполняется в контексте текущего объекта. Кроме того, он может принимать текущий объект в качестве аргумента.

Колбэки before и around вызываются в порядке их задания; колбэки after вызываются в обратном порядке.

Колбэки around могут получить возвращаемое событием значение, если оно не было остановлено, из вызова yield.

Параметры
  • :if — символ или массив символов, каждый из которых обозначает метод экземпляра или proc; колбэк будет вызван, только если все они вернут истинное значение.

    Если задан proc, его тело выполняется в контексте текущего объекта. Кроме того, он может принимать текущий объект в качестве аргумента.

  • :unless — символ или массив символов, каждый из которых обозначает метод экземпляра или proc; колбэк будет вызван, только если все они вернут ложное значение.

    Если задан proc, его тело выполняется в контексте текущего объекта. Кроме того, он может принимать текущий объект в качестве аргумента.

  • :prepend — если значение равно true, колбэк будет добавлен в начало существующей цепочки, а не в конец.

skip_callback (name, *filter_list, &block) Показать исходный код
# File activesupport/lib/active_support/callbacks.rb, line 788
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

Пропускает ранее заданный колбэк. Как и в случае с 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

Будет вызвано исключение ArgumentError, если колбэк ещё не был задан (за исключением случая, когда параметр :raise установлен в false).

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API