From 5359428a142239578b4d1dfb43dd8c417ab57b5c Mon Sep 17 00:00:00 2001 From: Eugene Kenny Date: Wed, 16 May 2018 22:40:20 +0100 Subject: Finalize transaction record state after real transaction After a real (non-savepoint) transaction has committed or rolled back, the original persistence-related state for all records modified in that transaction is discarded or restored, respectively. When the model has transactional callbacks, this happens synchronously in the `committed!` or `rolled_back!` methods; otherwise, it happens lazily the next time the record's persistence-related state is accessed. The synchronous code path always finalizes the state of the record, but the lazy code path only pops one "level" from the transaction counter, assuming it will always reach zero immediately after a real transaction. As the test cases included here demonstrate, that isn't always the case. By using the same logic as the synchronous code path, we ensure that the record's state is always updated after a real transaction has finished. --- activerecord/test/cases/transactions_test.rb | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'activerecord/test/cases') diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 17aeabe34e..0d7857c0cf 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -679,6 +679,35 @@ class TransactionTest < ActiveRecord::TestCase assert_not_predicate topic, :frozen? end + def test_restore_new_record_after_double_save + topic = Topic.new + + Topic.transaction do + topic.save! + topic.save! + raise ActiveRecord::Rollback + end + + assert_predicate topic, :new_record? + end + + def test_dont_restore_new_record_in_subsequent_transaction + topic = Topic.new + + Topic.transaction do + topic.save! + topic.save! + end + + Topic.transaction do + topic.save! + raise ActiveRecord::Rollback + end + + assert_predicate topic, :persisted? + assert_not_predicate topic, :new_record? + end + def test_restore_id_after_rollback topic = Topic.new -- cgit v1.2.3