From 4b6fb72199b5291363cb296b32946e4e78a15532 Mon Sep 17 00:00:00 2001 From: Adrianna Chang Date: Thu, 15 Jun 2023 17:44:04 -0400 Subject: [PATCH] Bugfix: Ensure has_one associations saved when part of CPK has changed If a has_one association uses a composite primary key, and part of the composite primary key changes on the owner, these changes need to be reflected on the belonging object's foreign key. This was not working previously, because `#_record_changed?` was not equipped to handle composite primary key associations, so we were not recognizing that the belonging object's foreign key needed to be updated when the owner's primary key changed. --- activerecord/lib/active_record/autosave_association.rb | 5 ++++- .../cases/associations/belongs_to_associations_test.rb | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 6ff41e4e9e705..dfd87fbfd743b 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -482,7 +482,10 @@ def _record_changed?(reflection, record, key) def association_foreign_key_changed?(reflection, record, key) return false if reflection.through_reflection? - record._has_attribute?(reflection.foreign_key) && record._read_attribute(reflection.foreign_key) != key + foreign_key = Array(reflection.foreign_key) + return false unless foreign_key.all? { |key| record._has_attribute?(key) } + + foreign_key.map { |key| record._read_attribute(key) } != Array(key) end def inverse_polymorphic_association_changed?(reflection, record) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index fabe8349dfeb4..e78a11c9a42db 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -376,6 +376,16 @@ def test_belongs_to_with_inverse_association_for_composite_primary_key assert_equal order_id, book.order_id end + def test_should_set_composite_foreign_key_on_association_when_key_changes_on_associated_record + book = Cpk::Book.create!(id: [1, 2], title: "The Well-Grounded Rubyist") + order = Cpk::Order.create!(id: [1, 2], book: book) + + order.shop_id = 3 + order.save! + + assert_equal 3, book.shop_id + end + def test_building_the_belonging_object_with_implicit_sti_base_class account = Account.new company = account.build_firm