1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activemodel/lib/active_model/callbacks.rb

135 lines
4.4 KiB
Ruby
Raw Normal View History

2010-03-27 14:50:11 -04:00
require 'active_support/core_ext/array/wrap'
require 'active_support/callbacks'
module ActiveModel
2010-06-15 14:18:10 -04:00
# == Active Model Callbacks
#
2010-01-14 16:19:53 -05:00
# Provides an interface for any class to have Active Record like callbacks.
#
2010-06-15 14:18:10 -04:00
# Like the Active Record methods, the callback chain is aborted as soon as
2010-01-14 16:19:53 -05:00
# one of the methods in the chain returns false.
#
# First, extend ActiveModel::Callbacks from the class you are creating:
#
2010-01-14 16:19:53 -05:00
# class MyModel
# extend ActiveModel::Callbacks
# end
#
2010-06-15 14:18:10 -04:00
# Then define a list of methods that you want callbacks attached to:
#
2010-01-14 16:19:53 -05:00
# 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
2010-06-15 14:18:10 -04:00
# you want callbacks on in a block so that the callbacks get a chance to fire:
#
2010-01-14 16:19:53 -05:00
# def create
# run_callbacks :create do
2010-01-14 16:19:53 -05:00
# # Your create action methods here
# end
# end
#
2010-01-14 16:19:53 -05:00
# 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.
#
2010-01-14 16:19:53 -05:00
# before_create :action_before_create
#
2010-01-14 16:19:53 -05:00
# def action_before_create
# # Your code here
# end
#
# You can choose not to have all three callbacks by passing a hash to the
2010-01-14 16:19:53 -05:00
# define_model_callbacks method.
#
2010-01-14 16:19:53 -05:00
# define_model_callbacks :create, :only => :after, :before
#
2010-01-14 16:19:53 -05:00
# Would only create the after_create and before_create callback methods in your
# class.
module Callbacks
def self.extended(base)
base.class_eval do
include ActiveSupport::Callbacks
end
end
# 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,
2010-01-14 16:19:53 -05:00
# where you can choose if you want all types (before, around or after) or just some.
#
2010-01-14 16:19:53 -05:00
# define_model_callbacks :initializer, :only => :after
#
2010-06-15 14:18:10 -04:00
# Note, the <tt>:only => <type></tt> hash will apply to all callbacks defined on
# that method call. To get around this you can call the define_model_callbacks
2010-01-14 16:19:53 -05:00
# method as many times as you need.
#
2010-01-14 16:19:53 -05:00
# define_model_callbacks :create, :only => :after
# define_model_callbacks :update, :only => :before
# define_model_callbacks :destroy, :only => :around
#
2010-01-14 16:19:53 -05:00
# Would create +after_create+, +before_update+ and +around_destroy+ methods only.
#
2010-01-14 16:19:53 -05:00
# You can pass in a class to before_<type>, after_<type> and around_<type>, in which
2010-06-15 14:18:10 -04:00
# case the callback will call that class's <action>_<type> method passing the object
# that the callback is being called on.
#
# class MyModel
2010-01-14 16:19:53 -05:00
# extend ActiveModel::Callbacks
# define_model_callbacks :create
#
2010-01-14 16:19:53 -05:00
# before_create AnotherClass
# end
#
2010-01-14 16:19:53 -05:00
# class AnotherClass
# def self.before_create( obj )
2010-06-15 14:18:10 -04:00
# # obj is the MyModel instance that the callback is being called on
# end
# end
#
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|
2010-12-27 03:30:36 -05:00
send("_define_#{type}_model_callback", self, callback)
end
end
end
def _define_before_model_callback(klass, callback) #:nodoc:
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
def self.before_#{callback}(*args, &block)
set_callback(:#{callback}, :before, *args, &block)
end
CALLBACK
end
def _define_around_model_callback(klass, callback) #:nodoc:
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
def self.around_#{callback}(*args, &block)
set_callback(:#{callback}, :around, *args, &block)
end
CALLBACK
end
def _define_after_model_callback(klass, callback) #:nodoc:
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
def self.after_#{callback}(*args, &block)
options = args.extract_options!
options[:prepend] = true
2010-03-27 14:50:11 -04:00
options[:if] = Array.wrap(options[:if]) << "!halted && value != false"
set_callback(:#{callback}, :after, *(args << options), &block)
end
CALLBACK
end
end
2010-03-27 14:50:11 -04:00
end