Skip to content

Commit 6ea0e91

Browse files
committed
Extend primary key methods to support composite keys
Let's consider the cases when primary key is composite for these methods, as this interface ends up being used in many codepaths across Rails.
1 parent 45b4917 commit 6ea0e91

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)