mirror of
https://github.com/github/rails.git
synced 2026-01-28 07:48:00 -05:00
Added database connection as a yield parameter to ActiveRecord::Base.transaction so you can manually rollback [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6196 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
*SVN*
|
||||
|
||||
* Added database connection as a yield parameter to ActiveRecord::Base.transaction so you can manually rollback [DHH]. Example:
|
||||
|
||||
transaction do |transaction|
|
||||
david.withdrawal(100)
|
||||
mary.deposit(100)
|
||||
transaction.rollback! # rolls back the transaction that was otherwise going to be successful
|
||||
end
|
||||
|
||||
* Made increment_counter/decrement_counter play nicely with optimistic locking, and added a more general update_counters method [Jamis Buck]
|
||||
|
||||
* Reworked David's query cache to be available as Model.cache {...}. For the duration of the block no select query should be run more then once. Any inserts/deletes/executes will flush the whole cache however [Tobias Luetke]
|
||||
|
||||
@@ -56,7 +56,7 @@ module ActiveRecord
|
||||
begin_db_transaction
|
||||
transaction_open = true
|
||||
end
|
||||
yield
|
||||
yield self
|
||||
end
|
||||
rescue Exception => database_transaction_rollback
|
||||
if transaction_open
|
||||
@@ -79,6 +79,11 @@ module ActiveRecord
|
||||
# done if the transaction block raises an exception or returns false.
|
||||
def rollback_db_transaction() end
|
||||
|
||||
# Alias for rollback_db_transaction to be used when yielding the transaction
|
||||
def rollback!
|
||||
rollback_db_transaction
|
||||
end
|
||||
|
||||
# Alias for #add_limit_offset!.
|
||||
def add_limit!(sql, options)
|
||||
add_limit_offset!(sql, options) if options
|
||||
|
||||
@@ -32,6 +32,17 @@ module ActiveRecord
|
||||
# Exceptions will force a ROLLBACK that returns the database to the state before the transaction was begun. Be aware, though,
|
||||
# that the objects by default will _not_ have their instance data returned to their pre-transactional state.
|
||||
#
|
||||
# == Rolling back a transaction manually
|
||||
#
|
||||
# Instead of relying on exceptions to rollback your transactions, you can also do so manually from within the scope
|
||||
# of the transaction by accepting a yield parameter and calling rollback! on it. Example:
|
||||
#
|
||||
# transaction do |transaction|
|
||||
# david.withdrawal(100)
|
||||
# mary.deposit(100)
|
||||
# transaction.rollback! # rolls back the transaction that was otherwise going to be successful
|
||||
# end
|
||||
#
|
||||
# == Transactions are not distributed across database connections
|
||||
#
|
||||
# A transaction acts on a single database connection. If you have
|
||||
|
||||
@@ -88,7 +88,7 @@ class TransactionTest < Test::Unit::TestCase
|
||||
|
||||
def test_failing_with_object_rollback
|
||||
assert !@first.approved?, "First should be unapproved initially"
|
||||
|
||||
|
||||
begin
|
||||
assert_deprecated /Object transactions/ do
|
||||
Topic.transaction(@first, @second) do
|
||||
@@ -168,6 +168,24 @@ class TransactionTest < Test::Unit::TestCase
|
||||
assert !Topic.find(2).approved?, "Second should have been unapproved"
|
||||
end
|
||||
|
||||
def test_manually_rolling_back_a_transaction
|
||||
Topic.transaction do |transaction|
|
||||
@first.approved = true
|
||||
@second.approved = false
|
||||
@first.save
|
||||
@second.save
|
||||
|
||||
transaction.rollback!
|
||||
end
|
||||
|
||||
assert @first.approved?, "First should still be changed in the objects"
|
||||
assert !@second.approved?, "Second should still be changed in the objects"
|
||||
|
||||
assert !Topic.find(1).approved?, "First shouldn't have been approved"
|
||||
assert Topic.find(2).approved?, "Second should still be approved"
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def add_exception_raising_after_save_callback_to_topic
|
||||
Topic.class_eval { def after_save() raise "Make the transaction rollback" end }
|
||||
|
||||
Reference in New Issue
Block a user