Kinjal Patel
Kinjal Patel

Reputation: 420

Can someone explain this find method behaviour?

Recently I moved from C# to ruby on rails and checking records in rails console, in which i accidently made typo mistake. Instead of using find() I used find{}. It is working but it always returns first record from table. I don't know how this happened.

When i googled this I found out that it has something to do with block but i didn't get any idea.

I typed Book.find{3} instead of Book.find(3)

Upvotes: 2

Views: 72

Answers (1)

Sebastián Palma
Sebastián Palma

Reputation: 33420

It's because when you pass a block to find it returns super:

def find(*ids) # :nodoc:
  # We don't have cache keys for this stuff yet
  return super unless ids.length == 1
  return super if block_given? ||
                  primary_key.nil? ...

  ...
end

Which then invokes find again, without a block and evaluating all other conditions as false:

return super unless ids.length == 1
return super if block_given? ||
                primary_key.nil? ||
                scope_attributes? ||
                columns_hash.key?(inheritance_column) && !base_class?

Allowing it to make a query to itself (the model, Book e.g) with a limit of 1:

...
statement = cached_find_by_statement(key) { |params|
  where(key => params.bind).limit(1)
}
...

Taking then the first element from the object statement, which is an ActiveRecord::StatementCache, similar to an ActiveRecord::Relationship object, holding 1 or more objects belonging to a model (Book in this case):

record = statement.execute([id], connection)&.first

Hence if statements is evaluated as truthy it is returned otherwise a RecordNotFound exception is raised:

record = statement.execute([id], connection)&.first
unless record
  raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
end
record

You can see this here.

Upvotes: 2

Related Questions