Module: ActiveModel::Callbacks

Defined in:
activemodel/lib/active_model/callbacks.rb

Overview

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 in the chain returns false.

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_create_callbacks do
      # Your create action methods here
    end
  end

The run_callbacks methods are dynamically created when you extend the ActiveModel::Callbacks module.

Then in your class, you can use the before_create, after_create and around_create methods, just as you would in an Active Record module.

  before_create :action_before_create

  def action_before_create
    # Your code here
  end

You can choose not to have all three 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.

Class Method Summary (collapse)

Instance Method Summary (collapse)

Class Method Details

+ (Object) extended(base)



52
53
54
55
56
# File 'activemodel/lib/active_model/callbacks.rb', line 52

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

Instance Method Details

- (Object) _define_after_model_callback(klass, callback)

:nodoc:



126
127
128
129
130
131
132
133
134
135
# File 'activemodel/lib/active_model/callbacks.rb', line 126

def _define_after_model_callback(klass, callback) #:nodoc:
  klass.class_eval <<-CALLBACK    def self.after_#{callback}(*args, &block)
      options = args.extract_options!
      options[:prepend] = true
      options[:if] = Array.wrap(options[:if]) << "!halted && value != false"
      set_callback(:#{callback}, __FILE__, __LINE__ + 1
, :after, *(args << options), &block)
    end
  CALLBACK
end

- (Object) _define_around_model_callback(klass, callback)

:nodoc:



118
119
120
121
122
123
124
# File 'activemodel/lib/active_model/callbacks.rb', line 118

def _define_around_model_callback(klass, callback) #:nodoc:
  klass.class_eval <<-CALLBACK    def self.around_#{callback}(*args, &block)
      set_callback(:#{callback}, __FILE__, __LINE__ + 1
, :around, *args, &block)
    end
  CALLBACK
end

- (Object) _define_before_model_callback(klass, callback)

:nodoc:



110
111
112
113
114
115
116
# File 'activemodel/lib/active_model/callbacks.rb', line 110

def _define_before_model_callback(klass, callback) #:nodoc:
  klass.class_eval <<-CALLBACK    def self.before_#{callback}(*args, &block)
      set_callback(:#{callback}, __FILE__, __LINE__ + 1
, :before, *args, &block)
    end
  CALLBACK
end

- (Object) 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 :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_, after_ and around_, in which case the callback will call that class’s _ 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


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'activemodel/lib/active_model/callbacks.rb', line 91

def define_model_callbacks(*callbacks)
  options = callbacks.extract_options!
  options = {
     :terminator => "result == false",
     :scope => [:kind, :name],
     :only => [:before, :around, :after]
  }.merge(options)

  types   = Array.wrap(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