123456789_123456789_123456789_123456789_123456789_

Module: ActiveModel::Callbacks

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: activemodel/lib/active_model/callbacks.rb

Overview

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 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: Defining the same callback multiple times will overwrite previous callback definitions.

Class Method Summary

Instance Method Summary

Class Method Details

.extended(base)

This method is for internal use only.
[ GitHub ]

  
# File 'activemodel/lib/active_model/callbacks.rb', line 66

def self.extended(base) # :nodoc:
  base.class_eval do
    include ActiveSupport::Callbacks
  end
end

Instance Method Details

#_define_after_model_callback(klass, callback) (private)

[ GitHub ]

  
# File 'activemodel/lib/active_model/callbacks.rb', line 143

def _define_after_model_callback(klass, callback)
  klass.define_singleton_method("after_#{callback}") do |*args, **options, &block|
    options.assert_valid_keys(:if, :unless, :prepend)
    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

#_define_around_model_callback(klass, callback) (private)

[ GitHub ]

  
# File 'activemodel/lib/active_model/callbacks.rb', line 136

def _define_around_model_callback(klass, callback)
  klass.define_singleton_method("around_#{callback}") do |*args, **options, &block|
    options.assert_valid_keys(:if, :unless, :prepend)
    set_callback(:"#{callback}", :around, *args, options, &block)
  end
end

#_define_before_model_callback(klass, callback) (private)

[ GitHub ]

  
# File 'activemodel/lib/active_model/callbacks.rb', line 129

def _define_before_model_callback(klass, callback)
  klass.define_singleton_method("before_#{callback}") do |*args, **options, &block|
    options.assert_valid_keys(:if, :unless, :prepend)
    set_callback(:"#{callback}", :before, *args, options, &block)
  end
end

#define_model_callbacks(*callbacks)

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 :initialize, 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 =.

[ GitHub ]

  
# File 'activemodel/lib/active_model/callbacks.rb', line 109

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