Skip to content

Commit d36fb65

Browse files
authored
Merge pull request rails#47979 from Shopify/pm/cpk-primary-key
Extend primary key methods to support composite keys
2 parents 9fc0681 + 6ea0e91 commit d36fb65

File tree

2 files changed

+70
-4
lines changed

2 files changed

+70
-4
lines changed

activerecord/lib/active_record/attribute_methods/primary_key.rb

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,29 @@ def id=(value)
3838

3939
# Queries the primary key column's value.
4040
def id?
41-
query_attribute(@primary_key)
41+
if self.class.composite_primary_key?
42+
@primary_key.all? { |col| query_attribute(col) }
43+
else
44+
query_attribute(@primary_key)
45+
end
4246
end
4347

4448
# Returns the primary key column's value before type cast.
4549
def id_before_type_cast
46-
attribute_before_type_cast(@primary_key)
50+
if self.class.composite_primary_key?
51+
@primary_key.map { |col| attribute_before_type_cast(col) }
52+
else
53+
attribute_before_type_cast(@primary_key)
54+
end
4755
end
4856

4957
# Returns the primary key column's previous value.
5058
def id_was
51-
attribute_was(@primary_key)
59+
if self.class.composite_primary_key?
60+
@primary_key.map { |col| attribute_was(col) }
61+
else
62+
attribute_was(@primary_key)
63+
end
5264
end
5365

5466
# Returns the primary key column's value from the database.
@@ -61,7 +73,11 @@ def id_in_database
6173
end
6274

6375
def id_for_database # :nodoc:
64-
@attributes[@primary_key].value_for_database
76+
if self.class.composite_primary_key?
77+
@primary_key.map { |col| @attributes[col].value_for_database }
78+
else
79+
@attributes[@primary_key].value_for_database
80+
end
6581
end
6682

6783
private

activerecord/test/cases/primary_keys_test.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ def test_to_key_with_primary_key_after_destroy
5353
assert_equal [1], topic.to_key
5454
end
5555

56+
def test_id_was
57+
topic = Topic.find(1)
58+
assert_equal 1, topic.id
59+
60+
topic.id = 3
61+
62+
assert_equal 1, topic.id_was
63+
assert_equal 3, topic.id
64+
end
65+
66+
def test_id?
67+
topic = Topic.find(1)
68+
69+
assert_changes("topic.id?", from: true, to: false) do
70+
topic.id = nil
71+
end
72+
end
73+
5674
def test_integer_key
5775
topic = Topic.find(1)
5876
assert_equal(topics(:first).author_name, topic.author_name)
@@ -413,6 +431,38 @@ def test_assigning_a_non_array_value_to_model_with_composite_primary_key_raises
413431
end
414432
end
415433

434+
def test_id_was_composite
435+
book = cpk_books(:cpk_great_author_first_book)
436+
book_id = book.id
437+
438+
assert_not_equal [42, 42], book_id
439+
440+
book.id = [42, 42]
441+
442+
assert_equal book_id, book.id_was
443+
assert_equal [42, 42], book.id
444+
end
445+
446+
def test_id_predicate_composite
447+
book = cpk_books(:cpk_great_author_first_book)
448+
449+
valid_id = [42, 42]
450+
451+
invalid_ids = [
452+
[42, nil],
453+
[nil, 42],
454+
[nil, nil],
455+
]
456+
457+
invalid_ids.each do |invalid_id|
458+
book.id = valid_id
459+
460+
assert_changes("book.id?", from: true, to: false) do
461+
book.id = invalid_id
462+
end
463+
end
464+
end
465+
416466
def test_primary_key_issues_warning
417467
model = Class.new(ActiveRecord::Base) do
418468
def self.table_name

0 commit comments

Comments
 (0)