Skip to content

Commit 1aac485

Browse files
authored
Merge pull request rails#47741 from Shopify/pm/cpk-rollback
Support composite primary keys during transaction rollback
2 parents 2cef3ac + 996d502 commit 1aac485

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

activerecord/lib/active_record/transactions.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,16 @@ def restore_transaction_record_state(force_restore_state = false)
416416
end
417417
@mutations_from_database = nil
418418
@mutations_before_last_save = nil
419-
if @attributes.fetch_value(@primary_key) != restore_state[:id]
420-
@attributes.write_from_user(@primary_key, restore_state[:id])
419+
if self.class.composite_primary_key?
420+
if restore_state[:id] != @primary_key.map { |col| @attributes.fetch_value(col) }
421+
@primary_key.zip(restore_state[:id]).each do |col, val|
422+
@attributes.write_from_user(col, val)
423+
end
424+
end
425+
else
426+
if @attributes.fetch_value(@primary_key) != restore_state[:id]
427+
@attributes.write_from_user(@primary_key, restore_state[:id])
428+
end
421429
end
422430
freeze if restore_state[:frozen?]
423431
end

activerecord/test/cases/transactions_test.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
require "models/author"
1010
require "models/post"
1111
require "models/movie"
12+
require "models/cpk"
1213

1314
class TransactionTest < ActiveRecord::TestCase
1415
self.use_transactional_tests = false
@@ -926,6 +927,32 @@ def test_restore_previously_new_record_after_double_save
926927
assert_predicate topic, :previously_new_record?
927928
end
928929

930+
def test_restore_composite_id_after_rollback
931+
book = Cpk::Book.create!(author_id: 1, number: 2)
932+
933+
Cpk::Book.transaction do
934+
book.update!(author_id: 42, number: 42)
935+
raise ActiveRecord::Rollback
936+
end
937+
938+
assert_equal [1, 2], book.id
939+
ensure
940+
Cpk::Book.delete_all
941+
end
942+
943+
def test_rollback_on_composite_key_model
944+
Cpk::Book.create!(author_id: 1, number: 3, title: "Charlotte's Web")
945+
book_two_unpersisted = Cpk::Book.new(author_id: 1, number: 3)
946+
947+
assert_raise(ActiveRecord::RecordNotUnique) do
948+
Cpk::Book.transaction do
949+
book_two_unpersisted.save!
950+
end
951+
end
952+
ensure
953+
Cpk::Book.delete_all
954+
end
955+
929956
def test_restore_id_after_rollback
930957
topic = Topic.new
931958

0 commit comments

Comments
 (0)