Skip to content

Commit 860ea32

Browse files
authored
Merge pull request rails#50412 from fatkodima/fix-find_by-for-cpks
Fix `find_by` for finding by associations with composite primary keys
2 parents 13265de + 6ca4408 commit 860ea32

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

activerecord/lib/active_record/core.rb

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,25 @@ def find_by(*args) # :nodoc:
275275
elsif reflection.belongs_to? && !reflection.polymorphic?
276276
key = reflection.join_foreign_key
277277
pkey = reflection.join_primary_key
278-
value = value.public_send(pkey) if value.respond_to?(pkey)
278+
279+
if pkey.is_a?(Array)
280+
if pkey.all? { |attribute| value.respond_to?(attribute) }
281+
value = pkey.map do |attribute|
282+
if attribute == "id"
283+
value.id_value
284+
else
285+
value.public_send(attribute)
286+
end
287+
end
288+
composite_primary_key = true
289+
end
290+
else
291+
value = value.public_send(pkey) if value.respond_to?(pkey)
292+
end
279293
end
280294

281-
if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
295+
if !composite_primary_key &&
296+
(!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
282297
return super
283298
end
284299

@@ -405,12 +420,18 @@ def table_metadata
405420

406421
def cached_find_by(keys, values)
407422
statement = cached_find_by_statement(keys) { |params|
408-
wheres = keys.index_with { params.bind }
423+
wheres = keys.index_with do |key|
424+
if key.is_a?(Array)
425+
[key.map { params.bind }]
426+
else
427+
params.bind
428+
end
429+
end
409430
where(wheres).limit(1)
410431
}
411432

412433
begin
413-
statement.execute(values, connection).first
434+
statement.execute(values.flatten, connection).first
414435
rescue TypeError
415436
raise ActiveRecord::StatementInvalid
416437
end

activerecord/test/cases/finder_test.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class FinderTest < ActiveRecord::TestCase
3434

3535
fixtures :companies, :topics, :entrants, :developers, :developers_projects,
3636
:posts, :comments, :accounts, :authors, :author_addresses, :customers,
37-
:categories, :categorizations, :cars, :clothing_items, :cpk_books
37+
:categories, :categorizations, :cars, :clothing_items, :cpk_books, :cpk_reviews
3838

3939
def test_find_by_id_with_hash
4040
assert_nothing_raised do
@@ -1875,6 +1875,22 @@ def test_finder_with_offset_string
18751875
assert_equal books.map(&:id), Cpk::Book.order(author_id: :asc).find(books.map(&:id)).map(&:id)
18761876
end
18771877

1878+
test "#find_by with composite primary key" do
1879+
book = cpk_books(:cpk_book_with_generated_pk)
1880+
assert_equal cpk_reviews(:first_book_review), Cpk::Review.find_by(book: book)
1881+
end
1882+
1883+
test "#find_by with composite primary key and query caching" do
1884+
book = cpk_books(:cpk_book_with_generated_pk)
1885+
1886+
Cpk::Review.cache do
1887+
assert_queries_count(1) do
1888+
Cpk::Review.find_by(book: book)
1889+
Cpk::Review.find_by(book: book)
1890+
end
1891+
end
1892+
end
1893+
18781894
private
18791895
def table_with_custom_primary_key
18801896
yield(Class.new(Toy) do

0 commit comments

Comments
 (0)