модуль ActiveSupport::Callbacks::ClassMethods
Публичные методы экземпляра
# File activesupport/lib/active_support/callbacks.rb, line 769
def define_callbacks(*names)
options = names.extract_options!
names.each do |name|
class_attribute "_#{name}_callbacks", instance_writer: false
set_callbacks name, CallbackChain.new(name, options)
module_eval " def _run_#{name}_callbacks(&block)
__run_callbacks__(_#{name}_callbacks, &block)
end
", __FILE__, __LINE__ + 1
end
end Определяет наборы событий в жизненном цикле объекта, поддерживающих обратные вызовы.
define_callbacks :validate define_callbacks :initialize, :save, :destroy
Параметры
-
:terminator- Определяет, когда фильтр before прервет цепочку обратных вызовов, предотвратив вызов последующих обратных вызовов и срабатывание события. Это должна быть лямбда-функция. Текущий объект и результат выполнения обратного вызова будут переданы в лямбда-функцию.define_callbacks :validate, terminator: ->(target, result) { result == false }В этом примере, если любой обратный вызов before validate возвращает
false, другие обратные вызовы не выполняются. По умолчанию этоfalse, что означает, что ни одно значение не прерывает цепочку. -
:skip_after_callbacks_if_terminated- Определяет, должны ли обратные вызовы after завершаться параметром:terminator. По умолчанию обратные вызовы after выполняются независимо от того, была ли прервана цепочка обратных вызовов или нет. Параметр имеет смысл только при указании параметра:terminator. -
: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.
ПРИМЕЧАНИЕ: method_name переданные в `define_model_callbacks` не должны заканчиваться символами `!`, `?` или `=`.
# File activesupport/lib/active_support/callbacks.rb, line 686
def reset_callbacks(name)
callbacks = get_callbacks name
ActiveSupport::DescendantsTracker.descendants(self).each do |target|
chain = target.get_callbacks(name).dup
callbacks.each { |c| chain.delete(c) }
target.set_callbacks name, chain
end
self.set_callbacks name, callbacks.dup.clear
end Удаляет все установленные обратные вызовы для заданного события.
# File activesupport/lib/active_support/callbacks.rb, line 647
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_meth
set_callback :save, :after, :after_meth, if: :condition
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
Второй аргумент указывает, должен ли обратный вызов выполняться :before, :after, или :around события. Если он опущен, предполагается :before. Это означает, что первый пример выше также можно записать как:
set_callback :save, :before_meth
Обратный вызов может быть задан как символ, обозначающий метод экземпляра; как проц, лямбда или блок; как строка для оценки экземпляра; или как объект, который отвечает на определённый метод, определяемый аргументом :scope к define_callbacks.
Если задан проц, лямбда или блок, его тело оценивается в контексте текущего объекта. Он также может по желанию принимать текущий объект в качестве аргумента.
Обратные вызовы before и around вызываются в порядке их установки; обратные вызовы after вызываются в обратном порядке.
Обратные вызовы around могут получить возвращаемое значение от события, если оно не было прервано, из вызова yield.
Параметры
-
:if- Символ, строка или массив символов и строк, каждый из которых обозначает метод экземпляра или проц; обратный вызов будет вызван только в том случае, если все они возвращают true. -
:unless- Символ, строка или массив символов и строк, каждый из которых обозначает метод экземпляра или проц; обратный вызов будет вызван только в том случае, если все они возвращают false. -
:prepend- Еслиtrue, обратный вызов будет добавлен в начало существующей цепочки, а не в конец.
# File activesupport/lib/active_support/callbacks.rb, line 667
def skip_callback(name, *filter_list, &block)
type, filters, options = normalize_callback_params(filter_list, block)
__update_callbacks(name) do |target, chain|
filters.each do |filter|
filter = chain.find {|c| c.matches?(type, filter) }
if filter && options.any?
new_filter = filter.merge(chain, options)
chain.insert(chain.index(filter), new_filter)
end
chain.delete(filter)
end
target.set_callbacks name, chain
end
end Пропустить ранее установленный обратный вызов. Как и в set_callback, параметры :if или :unless могут быть переданы для управления временем пропуска обратного вызова.
class Writer < Person
skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
end
Защищённые методы экземпляра
# File activesupport/lib/active_support/callbacks.rb, line 786
def get_callbacks(name)
send "_#{name}_callbacks"
end # File activesupport/lib/active_support/callbacks.rb, line 790
def set_callbacks(name, callbacks)
send "_#{name}_callbacks=", callbacks
end
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.