From cc4f368390d16b72666a2b24a61d5d3c82de5bdd Mon Sep 17 00:00:00 2001 From: Nikita Vasilevsky Date: Mon, 18 Mar 2024 18:40:11 +0000 Subject: [PATCH] Allow `primary_key:` association option to be composite Association's `primary_key` can be composite when derived from associated class `primary_key` or `query_constraints`. But we don't allow setting it explicitly even though Rails is already capable of supporting it. This commit allows `primary_key` association option to be an array. --- activerecord/lib/active_record/reflection.rb | 6 +++++- .../associations/belongs_to_associations_test.rb | 12 ++++++++++++ activerecord/test/models/cpk/book.rb | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 327fd82de7148..da7ff47d7421d 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -870,7 +870,11 @@ def association_class # klass option is necessary to support loading polymorphic associations def association_primary_key(klass = nil) if primary_key = options[:primary_key] - @association_primary_key ||= -primary_key.to_s + @association_primary_key ||= if primary_key.is_a?(Array) + primary_key.map { |pk| pk.to_s.freeze }.freeze + else + -primary_key.to_s + end elsif (klass || self.klass).has_query_constraints? || options[:query_constraints] (klass || self.klass).composite_query_constraints_list elsif (klass || self.klass).composite_primary_key? diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index d83e94bcbf5b5..86cc88c884d6c 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -371,6 +371,18 @@ def test_building_the_belonging_object_for_composite_primary_key assert_equal id, cpk_book.order_id end + def test_belongs_to_with_explicit_composite_primary_key + cpk_book = cpk_books(:cpk_great_author_first_book) + order = cpk_book.build_order_explicit_fk_pk + order.shop_id = 123 + cpk_book.save + + shop_id, id = order.id + assert_equal id, cpk_book.order_id + assert_equal shop_id, cpk_book.shop_id + assert_equal order, cpk_book.reload.order_explicit_fk_pk + end + def test_belongs_to_with_inverse_association_for_composite_primary_key author = Cpk::Author.new(name: "John") book = author.books.build(id: [nil, 1], title: "The Rails Way") diff --git a/activerecord/test/models/cpk/book.rb b/activerecord/test/models/cpk/book.rb index f882f9b55e968..0b3b20bae9462 100644 --- a/activerecord/test/models/cpk/book.rb +++ b/activerecord/test/models/cpk/book.rb @@ -6,6 +6,7 @@ class Book < ActiveRecord::Base self.table_name = :cpk_books belongs_to :order, autosave: true, query_constraints: [:shop_id, :order_id], counter_cache: true + belongs_to :order_explicit_fk_pk, class_name: "Cpk::Order", query_constraints: [:shop_id, :order_id], primary_key: [:shop_id, :id] belongs_to :author, class_name: "Cpk::Author" has_many :chapters, query_constraints: [:author_id, :book_id]