Skip to content

Commit 006eb25

Browse files
committed
Raise error on invalid fixture primary key
When you're using a custom primary key on a belongs_to and you're trying to load that value through the association shorthand in a fixture, you end up getting the primary key of the table and not the primary key specified in the join. This makes sense to keep as the behavior because it's super fast (just hashing the name of the fixture), but it's still surprising so we should want the developer that it's not possible to do what they want.
1 parent c9cdf74 commit 006eb25

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

activerecord/lib/active_record/fixture_set/table_row.rb

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,29 @@ def timestamp_column_names
3939
end
4040
end
4141

42+
class PrimaryKeyError < StandardError # :nodoc:
43+
def initialize(label, association, value)
44+
super(<<~MSG)
45+
Unable to set #{association.name} to #{value} because the association has a
46+
custom primary key (#{association.join_primary_key}) that does not match the
47+
associated table's primary key (#{association.klass.primary_key}).
48+
49+
To fix this, change your fixture from
50+
51+
#{label}:
52+
#{association.name}: #{value}
53+
54+
to
55+
56+
#{label}:
57+
#{association.foreign_key}: **value**
58+
59+
where **value** is the #{association.join_primary_key} value for the
60+
associated #{association.klass.name} record.
61+
MSG
62+
end
63+
end
64+
4265
def initialize(fixture, table_rows:, label:, now:)
4366
@table_rows = table_rows
4467
@label = label
@@ -119,9 +142,13 @@ def resolve_sti_reflections
119142
fk_name = association.join_foreign_key
120143

121144
if association.name.to_s != fk_name && value = @row.delete(association.name.to_s)
122-
if association.polymorphic? && value.sub!(/\s*\(([^)]*)\)\s*$/, "")
123-
# support polymorphic belongs_to as "label (Type)"
124-
@row[association.join_foreign_type] = $1
145+
if association.polymorphic?
146+
if value.sub!(/\s*\(([^)]*)\)\s*$/, "")
147+
# support polymorphic belongs_to as "label (Type)"
148+
@row[association.join_foreign_type] = $1
149+
end
150+
elsif association.join_primary_key != association.klass.primary_key
151+
raise PrimaryKeyError.new(@label, association, value)
125152
end
126153

127154
fk_type = reflection_class.type_for_attribute(fk_name).type

activerecord/test/cases/fixtures_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require "models/admin/account"
77
require "models/admin/randomly_named_c1"
88
require "models/admin/user"
9+
require "models/author"
910
require "models/binary"
1011
require "models/book"
1112
require "models/bulb"
@@ -18,6 +19,7 @@
1819
require "models/developer"
1920
require "models/dog"
2021
require "models/doubloon"
22+
require "models/essay"
2123
require "models/joke"
2224
require "models/matey"
2325
require "models/other_dog"
@@ -1492,6 +1494,16 @@ def self.file_fixture_path
14921494
end
14931495
end
14941496

1497+
class PrimaryKeyErrorTest < ActiveRecord::TestCase
1498+
test "generates the correct value" do
1499+
e = assert_raise(ActiveRecord::FixtureSet::TableRow::PrimaryKeyError) do
1500+
ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT + "/primary_key_error", "primary_key_error")
1501+
end
1502+
1503+
assert_includes e.message, "Unable to set"
1504+
end
1505+
end
1506+
14951507
if current_adapter?(:SQLite3Adapter) && !in_memory_db?
14961508
class MultipleFixtureConnectionsTest < ActiveRecord::TestCase
14971509
include ActiveRecord::TestFixtures
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
_fixture:
2+
model_class: Author
3+
4+
david:
5+
name: David
6+
owned_essay: a_modest_proposal

0 commit comments

Comments
 (0)