mirror of https://github.com/rails/rails
Don't call after_commit callbacks despite a record isn't saved
Regardless of a record isn't saved (e.g. validation is failed), `after_commit` / `after_rollback` callbacks are invoked for now. To fix the issue, this adds a record to the current transaction only when a record is actually saved. Fixes #29747. Closes #29833.
This commit is contained in:
parent
faf07d1468
commit
9252da9659
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
|
Loading…
Reference in New Issue