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.
This commit is contained in:
Kevin Newton 2021-02-10 11:29:13 -05:00
parent c9cdf7410e
commit 006eb25ccd
No known key found for this signature in database
GPG Key ID: FBE789CDA03B16F6
3 changed files with 48 additions and 3 deletions

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,6 @@
_fixture:
model_class: Author
david:
name: David
owned_essay: a_modest_proposal