Skip to content

Commit

Permalink
Merge pull request #50412 from fatkodima/fix-find_by-for-cpks
Browse files Browse the repository at this point in the history
Fix `find_by` for finding by associations with composite primary keys
  • Loading branch information
byroot committed Jan 4, 2024
2 parents 13265de + 6ca4408 commit 860ea32
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
29 changes: 25 additions & 4 deletions activerecord/lib/active_record/core.rb
Expand Up @@ -275,10 +275,25 @@ def find_by(*args) # :nodoc:
elsif reflection.belongs_to? && !reflection.polymorphic?
key = reflection.join_foreign_key
pkey = reflection.join_primary_key
value = value.public_send(pkey) if value.respond_to?(pkey)

if pkey.is_a?(Array)
if pkey.all? { |attribute| value.respond_to?(attribute) }
value = pkey.map do |attribute|
if attribute == "id"
value.id_value
else
value.public_send(attribute)
end
end
composite_primary_key = true
end
else
value = value.public_send(pkey) if value.respond_to?(pkey)
end
end

if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
if !composite_primary_key &&
(!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
return super
end

Expand Down Expand Up @@ -405,12 +420,18 @@ def table_metadata

def cached_find_by(keys, values)
statement = cached_find_by_statement(keys) { |params|
wheres = keys.index_with { params.bind }
wheres = keys.index_with do |key|
if key.is_a?(Array)
[key.map { params.bind }]
else
params.bind
end
end
where(wheres).limit(1)
}

begin
statement.execute(values, connection).first
statement.execute(values.flatten, connection).first
rescue TypeError
raise ActiveRecord::StatementInvalid
end
Expand Down
18 changes: 17 additions & 1 deletion activerecord/test/cases/finder_test.rb
Expand Up @@ -34,7 +34,7 @@ class FinderTest < ActiveRecord::TestCase

fixtures :companies, :topics, :entrants, :developers, :developers_projects,
:posts, :comments, :accounts, :authors, :author_addresses, :customers,
:categories, :categorizations, :cars, :clothing_items, :cpk_books
:categories, :categorizations, :cars, :clothing_items, :cpk_books, :cpk_reviews

def test_find_by_id_with_hash
assert_nothing_raised do
Expand Down Expand Up @@ -1875,6 +1875,22 @@ def test_finder_with_offset_string
assert_equal books.map(&:id), Cpk::Book.order(author_id: :asc).find(books.map(&:id)).map(&:id)
end

test "#find_by with composite primary key" do
book = cpk_books(:cpk_book_with_generated_pk)
assert_equal cpk_reviews(:first_book_review), Cpk::Review.find_by(book: book)
end

test "#find_by with composite primary key and query caching" do
book = cpk_books(:cpk_book_with_generated_pk)

Cpk::Review.cache do
assert_queries_count(1) do
Cpk::Review.find_by(book: book)
Cpk::Review.find_by(book: book)
end
end
end

private
def table_with_custom_primary_key
yield(Class.new(Toy) do
Expand Down

0 comments on commit 860ea32

Please sign in to comment.