/rails30-ruby19/classes/ActiveRecord/Callbacks.html
HTML | 387 lines | 320 code | 67 blank | 0 comment | 0 complexity | 57cfe5e498049ec5223176db5b602d95 MD5 | raw file
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <title>ActiveRecord::Callbacks</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <link rel="stylesheet" href="../../css/reset.css" type="text/css" media="screen" />
- <link rel="stylesheet" href="../../css/main.css" type="text/css" media="screen" />
- <script src="../../js/jquery-1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
- <script src="../../js/jquery-effect.js" type="text/javascript" charset="utf-8"></script>
- <script src="../../js/main.js" type="text/javascript" charset="utf-8"></script>
- </head>
- <body>
- <div class="banner">
- <h1>
- <span class="type">Module</span>
- ActiveRecord::Callbacks
-
- </h1>
- <ul class="files">
-
- <li><a href="../../files/activerecord/lib/active_record/callbacks_rb.html">activerecord/lib/active_record/callbacks.rb</a></li>
-
- </ul>
- </div>
- <div id="bodyContent">
- <div id="content">
-
- <div class="description">
- <h1>Active Record <a href="Callbacks.html">Callbacks</a></h1>
- <p>
- <a href="Callbacks.html">Callbacks</a> are hooks into the life cycle of an
- Active Record object that allow you to trigger logic before or after an
- alteration of the object state. This can be used to make sure that
- associated and dependent objects are deleted when <tt>destroy</tt> is
- called (by overwriting <tt>before_destroy</tt>) or to massage attributes
- before they’re validated (by overwriting <tt>before_validation</tt>).
- As an example of the callbacks initiated, consider the <tt>Base#save</tt>
- call for a new record:
- </p>
- <ul>
- <li>(-) <tt>save</tt>
- </li>
- <li>(-) <tt>valid</tt>
- </li>
- <li>(1) <tt>before_validation</tt>
- </li>
- <li>(-) <tt>validate</tt>
- </li>
- <li>(2) <tt>after_validation</tt>
- </li>
- <li>(3) <tt>before_save</tt>
- </li>
- <li>(4) <tt>before_create</tt>
- </li>
- <li>(-) <tt>create</tt>
- </li>
- <li>(5) <tt>after_create</tt>
- </li>
- <li>(6) <tt>after_save</tt>
- </li>
- <li>(7) <tt>after_commit</tt>
- </li>
- </ul>
- <p>
- Also, an <tt>after_rollback</tt> callback can be configured to be triggered
- whenever a rollback is issued. Check out
- <tt>ActiveRecord::Transactions</tt> for more details about
- <tt>after_commit</tt> and <tt>after_rollback</tt>.
- </p>
- <p>
- That’s a total of ten callbacks, which gives you immense power to
- react and prepare for each state in the Active Record life cycle. The
- sequence for calling <tt>Base#save</tt> for an existing record is similar,
- except that each <tt>_on_create</tt> callback is replaced by the
- corresponding <tt>_on_update</tt> callback.
- </p>
- <p>
- Examples:
- </p>
- <pre>
- class CreditCard < ActiveRecord::Base
- # Strip everything but digits, so the user can specify "555 234 34" or
- # "5552-3434" or both will mean "55523434"
- before_validation(:on => :create) do
- self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
- end
- end
- class Subscription < ActiveRecord::Base
- before_create :record_signup
- private
- def record_signup
- self.signed_up_on = Date.today
- end
- end
- class Firm < ActiveRecord::Base
- # Destroys the associated clients and people when the firm is destroyed
- before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
- before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
- end
- </pre>
- <h2>Inheritable callback queues</h2>
- <p>
- Besides the overwritable callback methods, it’s also possible to
- register callbacks through the use of the callback macros. Their main
- advantage is that the macros add behavior into a callback queue that is
- kept intact down through an inheritance hierarchy.
- </p>
- <pre>
- class Topic < ActiveRecord::Base
- before_destroy :destroy_author
- end
- class Reply < Topic
- before_destroy :destroy_readers
- end
- </pre>
- <p>
- Now, when <tt>Topic#destroy</tt> is run only <tt>destroy_author</tt> is
- called. When <tt>Reply#destroy</tt> is run, both <tt>destroy_author</tt>
- and <tt>destroy_readers</tt> are called. Contrast this to the following
- situation where the <tt>before_destroy</tt> methis is overriden:
- </p>
- <pre>
- class Topic < ActiveRecord::Base
- def before_destroy() destroy_author end
- end
- class Reply < Topic
- def before_destroy() destroy_readers end
- end
- </pre>
- <p>
- In that case, <tt>Reply#destroy</tt> would only run
- <tt>destroy_readers</tt> and <em>not</em> <tt>destroy_author</tt>. So, use
- the callback macros when you want to ensure that a certain callback is
- called for the entire hierarchy, and use the regular overwriteable methods
- when you want to leave it up to each descendant to decide whether they want
- to call <tt>super</tt> and trigger the inherited callbacks.
- </p>
- <p>
- <b>IMPORTANT:</b> In order for inheritance to work for the callback queues,
- you must specify the callbacks before specifying the associations.
- Otherwise, you might trigger the loading of a child before the parent has
- registered the callbacks and they won’t be inherited.
- </p>
- <h2>Types of callbacks</h2>
- <p>
- There are four types of callbacks accepted by the callback macros: Method
- references (symbol), callback objects, inline methods (using a proc), and
- inline eval methods (using a string). Method references and callback
- objects are the recommended approaches, inline methods using a proc are
- sometimes appropriate (such as for creating mix-ins), and inline eval
- methods are deprecated.
- </p>
- <p>
- The method reference callbacks work by specifying a protected or private
- method available in the object, like this:
- </p>
- <pre>
- class Topic < ActiveRecord::Base
- before_destroy :delete_parents
- private
- def delete_parents
- self.class.delete_all "parent_id = #{id}"
- end
- end
- </pre>
- <p>
- The callback objects have methods named after the callback called with the
- record as the only parameter, such as:
- </p>
- <pre>
- class BankAccount < ActiveRecord::Base
- before_save EncryptionWrapper.new
- after_save EncryptionWrapper.new
- after_initialize EncryptionWrapper.new
- end
- class EncryptionWrapper
- def before_save(record)
- record.credit_card_number = encrypt(record.credit_card_number)
- end
- def after_save(record)
- record.credit_card_number = decrypt(record.credit_card_number)
- end
- alias_method :after_find, :after_save
- private
- def encrypt(value)
- # Secrecy is committed
- end
- def decrypt(value)
- # Secrecy is unveiled
- end
- end
- </pre>
- <p>
- So you specify the object you want messaged on a given callback. When that
- callback is triggered, the object has a method by the name of the callback
- messaged. You can make these callbacks more flexible by passing in other
- initialization data such as the name of the attribute to work with:
- </p>
- <pre>
- class BankAccount < ActiveRecord::Base
- before_save EncryptionWrapper.new("credit_card_number")
- after_save EncryptionWrapper.new("credit_card_number")
- after_initialize EncryptionWrapper.new("credit_card_number")
- end
- class EncryptionWrapper
- def initialize(attribute)
- @attribute = attribute
- end
- def before_save(record)
- record.send("#{@attribute}=", encrypt(record.send("#{@attribute}")))
- end
- def after_save(record)
- record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
- end
- alias_method :after_find, :after_save
- private
- def encrypt(value)
- # Secrecy is committed
- end
- def decrypt(value)
- # Secrecy is unveiled
- end
- end
- </pre>
- <p>
- The callback macros usually accept a symbol for the method they’re
- supposed to run, but you can also pass a “method string”, which
- will then be evaluated within the binding of the callback. Example:
- </p>
- <pre>
- class Topic < ActiveRecord::Base
- before_destroy 'self.class.delete_all "parent_id = #{id}"'
- end
- </pre>
- <p>
- Notice that single quotes (’) are used so the <tt>#{id}</tt> part
- isn’t evaluated until the callback is triggered. Also note that these
- inline callbacks can be stacked just like the regular ones:
- </p>
- <pre>
- class Topic < ActiveRecord::Base
- before_destroy 'self.class.delete_all "parent_id = #{id}"',
- 'puts "Evaluated after parents are destroyed"'
- end
- </pre>
- <h2>The <tt>after_find</tt> and <tt>after_initialize</tt> exceptions</h2>
- <p>
- Because <tt>after_find</tt> and <tt>after_initialize</tt> are called for
- each object found and instantiated by a finder, such as
- <tt>Base.find(:all)</tt>, we’ve had to implement a simple performance
- constraint (50% more speed on a simple test case). Unlike all the other
- callbacks, <tt>after_find</tt> and <tt>after_initialize</tt> will only be
- run if an explicit implementation is defined (<tt>def after_find</tt>). In
- that case, all of the callback types will be called.
- </p>
- <h2><tt>before_validation*</tt> returning statements</h2>
- <p>
- If the returning value of a <tt>before_validation</tt> callback can be
- evaluated to <tt>false</tt>, the process will be aborted and
- <tt>Base#save</tt> will return <tt>false</tt>. If Base#save! is called it
- will raise a <a href="RecordInvalid.html">ActiveRecord::RecordInvalid</a>
- exception. Nothing will be appended to the errors object.
- </p>
- <h2>Canceling callbacks</h2>
- <p>
- If a <tt>before_*</tt> callback returns <tt>false</tt>, all the later
- callbacks and the associated action are cancelled. If an <tt>after_*</tt>
- callback returns <tt>false</tt>, all the later callbacks are cancelled. <a
- href="Callbacks.html">Callbacks</a> are generally run in the order they are
- defined, with the exception of callbacks defined as methods on the model,
- which are called last.
- </p>
- <h2><a href="Transactions.html">Transactions</a></h2>
- <p>
- The entire callback chain of a <tt>save</tt>, <tt>save!</tt>, or
- <tt>destroy</tt> call runs within a transaction. That includes
- <tt>after_*</tt> hooks. If everything goes fine a COMMIT is executed once
- the chain has been completed.
- </p>
- <p>
- If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued.
- You can also trigger a ROLLBACK raising an exception in any of the
- callbacks, including <tt>after_*</tt> hooks. Note, however, that in that
- case the client needs to be aware of it because an ordinary <tt>save</tt>
- will raise such exception instead of quietly returning <tt>false</tt>.
- </p>
- <h2>Debugging callbacks</h2>
- <p>
- To list the methods and procs registered with a particular callback, append
- <tt>_callback_chain</tt> to the callback name that you wish to list and
- send that to your class from the <a href="../Rails.html">Rails</a> console:
- </p>
- <pre>
- >> Topic.after_save_callback_chain
- => [#<ActiveSupport::Callbacks::Callback:0x3f6a448
- @method=#<Proc:0x03f9a42c@/Users/foo/bar/app/models/topic.rb:43>, kind:after_save, identifiernil,
- options{}]
- </pre>
- </div>
-
-
-
-
-
-
-
- <div class="sectiontitle">Included Modules</div>
- <ul>
-
- <li>
-
- <a href="../Rails.html">Rails</a>
-
- START:includes
- </li>
-
- </ul>
-
-
-
- <div class="sectiontitle">Classes and Modules</div>
- <ul>
-
- <li><span class="type">MODULE</span> <a href="Callbacks/ClassMethods.html">ActiveRecord::Callbacks::ClassMethods</a></li>
-
- </ul>
-
-
- <div class="sectiontitle">Constants</div>
- <table border='0' cellpadding='5'>
-
- <tr valign='top'>
- <td class="attr-name">CALLBACKS</td>
- <td>=</td>
- <td class="attr-value">[ :after_initialize, :after_find, :after_touch, :before_validation, :after_validation, :before_save, :around_save, :after_save, :before_create, :around_create, :after_create, :before_update, :around_update, :after_update, :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback ]</td>
- </tr>
-
-
- </table>
-
-
-
- </div>
- </div>
- </body>
- </html>