module ActiveModel::Callbacks
Active Model Callbacks¶ ↑
Provides an interface for any class to have Active Record like callbacks.
Like the Active Record methods, the callback chain is aborted as soon as
one of the methods throws :abort
.
First, extend ActiveModel::Callbacks from the class you are creating:
class MyModel extend ActiveModel::Callbacks end
Then define a list of methods that you want callbacks attached to:
define_model_callbacks :create, :update
This will provide all three standard callbacks (before, around and after)
for both the :create
and :update
methods. To
implement, you need to wrap the methods you want callbacks on in a block so
that the callbacks get a chance to fire:
def create run_callbacks :create do # Your create action methods here end end
Then in your class, you can use the before_create
,
after_create
and around_create
methods, just as
you would in an Active Record model.
before_create :action_before_create def action_before_create # Your code here end
When defining an around callback remember to yield to the block, otherwise it won't be executed:
around_create :log_status def log_status puts 'going to call the block...' yield puts 'block successfully called.' end
You can choose to have only specific callbacks by passing a hash to the
define_model_callbacks
method.
define_model_callbacks :create, only: [:after, :before]
Would only create the after_create
and
before_create
callback methods in your class.
NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
Public Instance Methods
#define_model_callbacks
accepts the same options define_callbacks
does, in case you
want to overwrite a default. Besides that, it also accepts an
:only
option, where you can choose if you want all types
(before, around or after) or just some.
define_model_callbacks :initializer, only: :after
Note, the only: <type>
hash will apply to all callbacks
defined on that method call. To get around this you can call the #define_model_callbacks
method as many times as you need.
define_model_callbacks :create, only: :after define_model_callbacks :update, only: :before define_model_callbacks :destroy, only: :around
Would create after_create
, before_update
and
around_destroy
methods only.
You can pass in a class to before_<type>, after_<type> and around_<type>, in which case the callback will call that class's <action>_<type> method passing the object that the callback is being called on.
class MyModel extend ActiveModel::Callbacks define_model_callbacks :create before_create AnotherClass end class AnotherClass def self.before_create( obj ) # obj is the MyModel instance that the callback is being called on end end
NOTE: method_name
passed to #define_model_callbacks
must not end with !
, ?
or =
.
# File lib/active_model/callbacks.rb, line 107 def define_model_callbacks(*callbacks) options = callbacks.extract_options! options = { skip_after_callbacks_if_terminated: true, scope: [:kind, :name], only: [:before, :around, :after] }.merge!(options) types = Array(options.delete(:only)) callbacks.each do |callback| define_callbacks(callback, options) types.each do |type| send("_define_#{type}_model_callback", self, callback) end end end
Private Instance Methods
# File lib/active_model/callbacks.rb, line 140 def _define_after_model_callback(klass, callback) klass.define_singleton_method("after_#{callback}") do |*args, &block| options = args.extract_options! options[:prepend] = true conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v| v != false } options[:if] = Array(options[:if]) << conditional set_callback(:"#{callback}", :after, *(args << options), &block) end end
# File lib/active_model/callbacks.rb, line 134 def _define_around_model_callback(klass, callback) klass.define_singleton_method("around_#{callback}") do |*args, &block| set_callback(:"#{callback}", :around, *args, &block) end end
# File lib/active_model/callbacks.rb, line 128 def _define_before_model_callback(klass, callback) klass.define_singleton_method("before_#{callback}") do |*args, &block| set_callback(:"#{callback}", :before, *args, &block) end end