aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2019-04-12 22:10:04 +0900
committerGitHub <noreply@github.com>2019-04-12 22:10:04 +0900
commit186566c58a559452883ae9f7a2d837ebf40be1f4 (patch)
treeb1542673205237111b916d52da20f6ee8dced411
parent8c249086823eecd23e2e7bd6084ca30ee0e0f6d5 (diff)
parent9252da96597fbffe2246704556524c4804239552 (diff)
downloadrails-186566c58a559452883ae9f7a2d837ebf40be1f4.tar.gz
rails-186566c58a559452883ae9f7a2d837ebf40be1f4.tar.bz2
rails-186566c58a559452883ae9f7a2d837ebf40be1f4.zip
Merge pull request #35920 from kamipo/dont_call_commit_callbacks_for_invalid_record
Don't call after_commit callbacks despite a record isn't saved
-rw-r--r--activerecord/CHANGELOG.md6
-rw-r--r--activerecord/lib/active_record/transactions.rb12
-rw-r--r--activerecord/test/cases/callbacks_test.rb4
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb26
4 files changed, 43 insertions, 5 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 1cf3f3352f..3b8767787f 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Don't call commit/rollback callbacks despite a record isn't saved.
+
+ Fixes #29747.
+
+ *Ryuta Kamizono*
+
* Fix circular `autosave: true` causes invalid records to be saved.
Prior to the fix, when there was a circular series of `autosave: true`
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index a45d228298..333f1a5435 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -376,9 +376,19 @@ module ActiveRecord
def with_transaction_returning_status
status = nil
self.class.transaction do
- add_to_transaction
+ unless has_transactional_callbacks?
+ sync_with_transaction_state
+ set_transaction_state(self.class.connection.transaction_state)
+ end
+ remember_transaction_record_state
+
status = yield
raise ActiveRecord::Rollback unless status
+ ensure
+ if has_transactional_callbacks? &&
+ (@_new_record_before_last_commit && !new_record? || _trigger_update_callback || _trigger_destroy_callback)
+ self.class.connection.add_transaction_record(self)
+ end
end
status
end
diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb
index 4d6a112af5..b4026078f1 100644
--- a/activerecord/test/cases/callbacks_test.rb
+++ b/activerecord/test/cases/callbacks_test.rb
@@ -458,10 +458,6 @@ class CallbacksTest < ActiveRecord::TestCase
[ :before_validation, :object ],
[ :before_validation, :block ],
[ :before_validation, :throwing_abort ],
- [ :after_rollback, :block ],
- [ :after_rollback, :object ],
- [ :after_rollback, :proc ],
- [ :after_rollback, :method ],
], david.history
end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index e88d20a453..cd73f6082e 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -111,6 +111,32 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
assert_equal [:after_commit], @first.history
end
+ def test_dont_call_any_callbacks_after_transaction_commits_for_invalid_record
+ @first.after_commit_block { |r| r.history << :after_commit }
+ @first.after_rollback_block { |r| r.history << :after_rollback }
+
+ def @first.valid?(*)
+ false
+ end
+
+ assert_not @first.save
+ assert_equal [], @first.history
+ end
+
+ def test_dont_call_any_callbacks_after_explicit_transaction_commits_for_invalid_record
+ @first.after_commit_block { |r| r.history << :after_commit }
+ @first.after_rollback_block { |r| r.history << :after_rollback }
+
+ def @first.valid?(*)
+ false
+ end
+
+ @first.transaction do
+ assert_not @first.save
+ end
+ assert_equal [], @first.history
+ end
+
def test_only_call_after_commit_on_save_after_transaction_commits_for_saving_record
record = TopicWithCallbacks.new(title: "New topic", written_on: Date.today)
record.after_commit_block(:save) { |r| r.history << :after_save }