aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Neves <arthurnn@gmail.com>2015-02-12 23:06:44 -0500
committerArthur Neves <arthurnn@gmail.com>2015-02-24 19:13:56 -0500
commit4a1bb9d0ce985fd105f930078a733601b29ef8a4 (patch)
tree3d6ac1c3e44f3646ecd0833e13ef0f6acf39ea3f
parent62133326df3c7edff67a2e57ae32c95bf6e8a818 (diff)
downloadrails-4a1bb9d0ce985fd105f930078a733601b29ef8a4.tar.gz
rails-4a1bb9d0ce985fd105f930078a733601b29ef8a4.tar.bz2
rails-4a1bb9d0ce985fd105f930078a733601b29ef8a4.zip
Add transaction callbacks that wont enroll to the transaction.
Add after_commit_without_transaction_enrollment and after_rollback_without_transaction_enrollment private callbacks so we can create after_commit and after_rollback callbacks without having the records automatic enrolled in the transaction. [fixes #18904]
-rw-r--r--activerecord/lib/active_record/transactions.rb22
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb59
2 files changed, 79 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index dd405c7796..e6580c9930 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -7,6 +7,8 @@ module ActiveRecord
included do
define_callbacks :commit, :rollback,
+ :commit_without_transaction_enrollment,
+ :rollback_without_transaction_enrollment,
scope: [:kind, :name]
end
@@ -233,6 +235,16 @@ module ActiveRecord
set_callback(:rollback, :after, *args, &block)
end
+ def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
+ set_options_for_callbacks!(args)
+ set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
+ end
+
+ def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
+ set_options_for_callbacks!(args)
+ set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
+ end
+
def raise_in_transactional_callbacks
ActiveSupport::Deprecation.warn('ActiveRecord::Base.raise_in_transactional_callbacks is deprecated and will be removed without replacement.')
true
@@ -301,7 +313,10 @@ module ActiveRecord
# Ensure that it is not called if the object was never persisted (failed create),
# but call it after the commit of a destroyed object.
def committed!(should_run_callbacks: true) #:nodoc:
- _run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
+ if should_run_callbacks && destroyed? || persisted?
+ _run_commit_without_transaction_enrollment_callbacks
+ _run_commit_callbacks
+ end
ensure
force_clear_transaction_record_state
end
@@ -309,7 +324,10 @@ module ActiveRecord
# Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
# state should be rolled back to the beginning or just to the last savepoint.
def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
- _run_rollback_callbacks if should_run_callbacks
+ if should_run_callbacks
+ _run_rollback_without_transaction_enrollment_callbacks
+ _run_rollback_callbacks
+ end
ensure
restore_transaction_record_state(force_restore_state)
clear_transaction_record_state
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index f185cda263..60b0fd4112 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -400,3 +400,62 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
assert_equal [:update_and_destroy, :create_and_destroy], topic.history
end
end
+
+
+class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase
+
+ class TopicWithoutTransactionalEnrollmentCallbacks < ActiveRecord::Base
+ self.table_name = :topics
+
+ after_commit_without_transaction_enrollment { |r| r.history << :commit }
+ after_rollback_without_transaction_enrollment { |r| r.history << :rollback }
+
+ def history
+ @history ||= []
+ end
+ end
+
+ def setup
+ @topic = TopicWithoutTransactionalEnrollmentCallbacks.create!
+ end
+
+ def test_commit_dont_enroll_transaction
+ @topic.transaction do
+ @topic.content = 'foo'
+ @topic.save!
+ end
+ assert @topic.history.empty?
+ end
+
+ def test_commit_enrollment_transaction_when_call_add
+ @topic.transaction do
+ 2.times do
+ @topic.content = 'foo'
+ @topic.save!
+ end
+ @topic.class.connection.add_transaction_record(@topic)
+ end
+ assert_equal [:commit], @topic.history
+ end
+
+ def test_rollback_dont_enroll_transaction
+ @topic.transaction do
+ @topic.content = 'foo'
+ @topic.save!
+ raise ActiveRecord::Rollback
+ end
+ assert @topic.history.empty?
+ end
+
+ def test_rollback_enrollment_transaction_when_call_add
+ @topic.transaction do
+ 2.times do
+ @topic.content = 'foo'
+ @topic.save!
+ end
+ @topic.class.connection.add_transaction_record(@topic)
+ raise ActiveRecord::Rollback
+ end
+ assert_equal [:rollback], @topic.history
+ end
+end