diff --git a/activerecord/lib/active_record/fixture_set/table_row.rb b/activerecord/lib/active_record/fixture_set/table_row.rb index 6b4c7a935fb..c96c0fed62c 100644 --- a/activerecord/lib/active_record/fixture_set/table_row.rb +++ b/activerecord/lib/active_record/fixture_set/table_row.rb @@ -39,6 +39,29 @@ module ActiveRecord end end + class PrimaryKeyError < StandardError # :nodoc: + def initialize(label, association, value) + super(<<~MSG) + Unable to set #{association.name} to #{value} because the association has a + custom primary key (#{association.join_primary_key}) that does not match the + associated table's primary key (#{association.klass.primary_key}). + + To fix this, change your fixture from + + #{label}: + #{association.name}: #{value} + + to + + #{label}: + #{association.foreign_key}: **value** + + where **value** is the #{association.join_primary_key} value for the + associated #{association.klass.name} record. + MSG + end + end + def initialize(fixture, table_rows:, label:, now:) @table_rows = table_rows @label = label @@ -119,9 +142,13 @@ module ActiveRecord fk_name = association.join_foreign_key if association.name.to_s != fk_name && value = @row.delete(association.name.to_s) - if association.polymorphic? && value.sub!(/\s*\(([^)]*)\)\s*$/, "") - # support polymorphic belongs_to as "label (Type)" - @row[association.join_foreign_type] = $1 + if association.polymorphic? + if value.sub!(/\s*\(([^)]*)\)\s*$/, "") + # support polymorphic belongs_to as "label (Type)" + @row[association.join_foreign_type] = $1 + end + elsif association.join_primary_key != association.klass.primary_key + raise PrimaryKeyError.new(@label, association, value) end fk_type = reflection_class.type_for_attribute(fk_name).type diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index a466cccac9d..dfd90c14aba 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -6,6 +6,7 @@ require "models/admin" require "models/admin/account" require "models/admin/randomly_named_c1" require "models/admin/user" +require "models/author" require "models/binary" require "models/book" require "models/bulb" @@ -18,6 +19,7 @@ require "models/course" require "models/developer" require "models/dog" require "models/doubloon" +require "models/essay" require "models/joke" require "models/matey" require "models/other_dog" @@ -1492,6 +1494,16 @@ class FileFixtureConflictTest < ActiveRecord::TestCase end end +class PrimaryKeyErrorTest < ActiveRecord::TestCase + test "generates the correct value" do + e = assert_raise(ActiveRecord::FixtureSet::TableRow::PrimaryKeyError) do + ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT + "/primary_key_error", "primary_key_error") + end + + assert_includes e.message, "Unable to set" + end +end + if current_adapter?(:SQLite3Adapter) && !in_memory_db? class MultipleFixtureConnectionsTest < ActiveRecord::TestCase include ActiveRecord::TestFixtures diff --git a/activerecord/test/fixtures/primary_key_error/primary_key_error.yml b/activerecord/test/fixtures/primary_key_error/primary_key_error.yml new file mode 100644 index 00000000000..b5edcec4ace --- /dev/null +++ b/activerecord/test/fixtures/primary_key_error/primary_key_error.yml @@ -0,0 +1,6 @@ +_fixture: + model_class: Author + +david: + name: David + owned_essay: a_modest_proposal