From de1cf736b3e2a3f9b9a7a84c4edfba71ebaf4f69 Mon Sep 17 00:00:00 2001 From: Brian Durand Date: Tue, 18 Jan 2011 08:58:57 -0600 Subject: [PATCH 4/4] document after transaction callbacks --- .../active_record_validations_callbacks.textile | 39 +++++++++++++++++++- 1 files changed, 37 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index a15571f..e8009ac 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -866,7 +866,7 @@ class User < ActiveRecord::Base validates_presence_of :login, :email before_create {|user| user.name = user.login.capitalize - if user.name.blank?} + if user.name.blank?} end @@ -986,7 +986,7 @@ As you start registering new callbacks for your models, they will be queued for The whole callback chain is wrapped in a transaction. If any before callback method returns exactly +false+ or raises an exception the execution chain gets halted and a ROLLBACK is issued; after callbacks can only accomplish that by raising an exception. -WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised. +WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is used precisely to tell Active Record to rollback the transaction. That one is internally captured but not re-raised. h3. Relational Callbacks @@ -1158,8 +1158,43 @@ In this example, the +after_create+ method would be called whenever a +Registrat config.active_record.observers = :mailer_observer +h3. Transaction Callbacks + +There are two additional callbacks that are triggered by the completion of a database transaction: +after_commit+ and +after_rollback+. These callbacks are very similar to the +after_save+ callback except that they don't execute until after database changes have either been committed or rolled back. They are most useful when your active record models need to interact with external systems which are not part of the database transaction. + +Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after a record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error. + + +PictureFile.transaction do + picture_file_1.destroy + picture_file_2.save! +end + + +By using the +after_commit+ callback we can account for this case. + + +class PictureFile < ActiveRecord::Base + attr_accessor :delete_file + + after_destroy do |picture_file| + picture_file.delete_file = picture_file.filepath + end + + after_commit do |picture_file| + if picture_file.delete_file && File.exist?(picture_file.delete_file) + File.delete(picture_file.delete_file) + picture_file.delete_file = nil + end + end +end + + +The +after_commit+ and +after_rollback+ callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback. + h3. Changelog +* January 18, 2011: Add description of transaction callbacks. * July 20, 2010: Fixed typos and rephrased some paragraphs for clarity. "Jaime Iniesta":http://jaimeiniesta.com * May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * May 15, 2010: Validation Errors section updated by "Emili ParreƱo":http://www.eparreno.com -- 1.7.3.4