From 851fb27ae3a70a9c41e9345b520af2a17c9d51d0 Mon Sep 17 00:00:00 2001 From: Nikita Vasilevsky Date: Wed, 5 Apr 2023 17:32:59 +0000 Subject: [PATCH] Reset composite primary key in `#dup` This commit ensures that the composite primary key is reset when `#dup` is called on an instance of an `ActiveRecord::Base` subclass. For example: ```ruby class TravelRoute < ActiveRecord::Base self.primary_key = [:origin, :destination] end route = TravelRoute.new(origin: "NYC", destination: "LAX") route.dup # => # ``` --- activerecord/lib/active_record/core.rb | 6 +++++- activerecord/test/cases/base_test.rb | 14 +++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 72d72a7325..d90b284e58 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -507,7 +507,11 @@ def init_with_attributes(attributes, new_record = false) # :nodoc: ## def initialize_dup(other) # :nodoc: @attributes = @attributes.deep_dup - @attributes.reset(@primary_key) + if self.class.composite_primary_key? + @primary_key.each { |key| @attributes.reset(key) } + else + @attributes.reset(@primary_key) + end _run_initialize_callbacks diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index a3ba41244d..2df0447d04 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -28,6 +28,7 @@ require "models/bulb" require "models/pet" require "models/owner" +require "models/cpk/book" require "concurrent/atomic/count_down_latch" require "active_support/core_ext/enumerable" require "active_support/core_ext/kernel/reporting" @@ -101,7 +102,9 @@ def setup end class BasicsTest < ActiveRecord::TestCase - fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, "warehouse-things", :authors, :author_addresses, :categorizations, :categories, :posts + fixtures :topics, :companies, :developers, :projects, :computers, :accounts, + :minimalistics, "warehouse-things", :authors, :author_addresses, :categorizations, :categories, + :posts, :cpk_books def test_generated_association_methods_module_name mod = Post.send(:generated_association_methods) @@ -1002,6 +1005,15 @@ def test_dup assert_equal("c", duped_topic.title) end + def test_dup_for_a_composite_primary_key_model + book = cpk_books(:cpk_great_author_first_book) + new_book = book.dup + + assert_equal "The first book", new_book.title + assert_nil new_book.author_id + assert_nil new_book.number + end + DeveloperSalary = Struct.new(:amount) def test_dup_with_aggregate_of_same_name_as_attribute developer_with_aggregate = Class.new(ActiveRecord::Base) do