aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG4
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb8
-rw-r--r--activerecord/lib/active_record/transactions.rb24
-rw-r--r--activerecord/test/transactions_test.rb2
4 files changed, 20 insertions, 18 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 7e26b3c10a..a82f8a0013 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,9 @@
*SVN*
+* Fixed that nested transactions now work by letting the outer most transaction have the responsibilty of starting and rolling back the transaction.
+ If any of the inner transactions swallow the exception raised, though, the transaction will not be rolled back. So always let the transaction
+ bubble up even when you've dealt with local issues. Closes #231 and #340.
+
* Fixed validates_{confirmation,acceptance}_of to only happen when the virtual attributes are not nil #348 [dpiddy@gmail.com]
* Added a require_association hook on const_missing that makes it possible to use any model class without requiring it first. This makes STI look like:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index b521a0fdf8..d41356ffa4 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -298,16 +298,16 @@ module ActiveRecord
end
# Wrap a block in a transaction. Returns result of block.
- def transaction
+ def transaction(start_db_transaction = true)
begin
if block_given?
- begin_db_transaction
+ begin_db_transaction if start_db_transaction
result = yield
- commit_db_transaction
+ commit_db_transaction if start_db_transaction
result
end
rescue Exception => database_transaction_rollback
- rollback_db_transaction
+ rollback_db_transaction if start_db_transaction
raise
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index d440e74346..16c56c58f0 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -77,13 +77,17 @@ module ActiveRecord
# Tribute: Object-level transactions are implemented by Transaction::Simple by Austin Ziegler.
module ClassMethods
def transaction(*objects, &block)
- TRANSACTION_MUTEX.lock
+ TRANSACTION_MUTEX.synchronize do
+ Thread.current['open_transactions'] ||= 0
+ Thread.current['start_db_transaction'] = (Thread.current['open_transactions'] == 0)
+ Thread.current['open_transactions'] += 1
+ end
begin
objects.each { |o| o.extend(Transaction::Simple) }
objects.each { |o| o.start_transaction }
- result = connection.transaction(&block)
+ result = connection.transaction(Thread.current['start_db_transaction'], &block)
objects.each { |o| o.commit_transaction }
return result
@@ -91,7 +95,9 @@ module ActiveRecord
objects.each { |o| o.abort_transaction }
raise
ensure
- TRANSACTION_MUTEX.unlock
+ TRANSACTION_MUTEX.synchronize do
+ Thread.current['open_transactions'] -= 1
+ end
end
end
end
@@ -101,19 +107,11 @@ module ActiveRecord
end
def destroy_with_transactions #:nodoc:
- if TRANSACTION_MUTEX.locked?
- destroy_without_transactions
- else
- transaction { destroy_without_transactions }
- end
+ transaction { destroy_without_transactions }
end
def save_with_transactions(perform_validation = true) #:nodoc:
- if TRANSACTION_MUTEX.locked?
- save_without_transactions(perform_validation)
- else
- transaction { save_without_transactions(perform_validation) }
- end
+ transaction { save_without_transactions(perform_validation) }
end
end
end
diff --git a/activerecord/test/transactions_test.rb b/activerecord/test/transactions_test.rb
index 18b2ea3e65..cf10b7d3ee 100644
--- a/activerecord/test/transactions_test.rb
+++ b/activerecord/test/transactions_test.rb
@@ -84,7 +84,7 @@ class TransactionTest < Test::Unit::TestCase
end
end
- def xtest_nested_explicit_transactions
+ def test_nested_explicit_transactions
Topic.transaction do
Topic.transaction do
@first.approved = 1