Skip to content

Commit 45b4917

Browse files
authored
Merge pull request rails#47968 from Shopify/pm/uniqueness-validation-cpk
Fix uniqueness validation, #id_in_database can be composite
2 parents 732a474 + 4896b6c commit 45b4917

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

activerecord/lib/active_record/attribute_methods/primary_key.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ def id_was
5353

5454
# Returns the primary key column's value from the database.
5555
def id_in_database
56-
attribute_in_database(@primary_key)
56+
if self.class.composite_primary_key?
57+
@primary_key.map { |col| attribute_in_database(col) }
58+
else
59+
attribute_in_database(@primary_key)
60+
end
5761
end
5862

5963
def id_for_database # :nodoc:

activerecord/lib/active_record/validations/uniqueness.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def validate_each(record, attribute, value)
2525
relation = build_relation(finder_class, attribute, value)
2626
if record.persisted?
2727
if finder_class.primary_key
28-
relation = relation.where.not(finder_class.primary_key => record.id_in_database)
28+
relation = relation.where.not(finder_class.primary_key => [record.id_in_database])
2929
else
3030
raise UnknownPrimaryKey.new(finder_class, "Cannot validate uniqueness for persisted record without primary key.")
3131
end

activerecord/test/cases/validations/uniqueness_validation_test.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
require "models/person"
1313
require "models/essay"
1414
require "models/keyboard"
15+
require "models/cpk"
1516

1617
class Wizard < ActiveRecord::Base
1718
self.abstract_class = true
@@ -811,3 +812,22 @@ def test_index_of_columns_list_and_extra_columns
811812
end
812813
end
813814
end
815+
816+
class UniquenessWithCompositeKey < ActiveRecord::TestCase
817+
class BookWithUniqueRevision < Cpk::Book
818+
validates :revision, uniqueness: true
819+
end
820+
821+
def test_uniqueness_validation_for_model_with_composite_key
822+
book_one = BookWithUniqueRevision.create!(author_id: 1, number: 42, title: "Author 1's book", revision: 36)
823+
book_two = BookWithUniqueRevision.create!(author_id: 2, number: 42, title: "Author 2's book", revision: 37)
824+
825+
assert_not_equal book_one.revision, book_two.revision
826+
827+
assert_changes("book_two.valid?", from: true, to: false) do
828+
book_two.revision = book_one.revision
829+
end
830+
ensure
831+
BookWithUniqueRevision.delete_all
832+
end
833+
end

0 commit comments

Comments
 (0)