50

What's the difference between find, where and find_by_id? They all work when you try to find a user given an ID.

Rosa
  • 642
  • 6
  • 20

5 Answers5

74

The difference is what they return when a record is found, or when it's not found. Consider the following examples:

>> User.create name: 'THE USER' # creates a user with id = 1
>> User.find(1) # returns the user
>> User.find_by_id(1) # returns the user
>> User.where(id: 1).first # returns the user

As you can see, an existing user can be fetched using any of the 3 methods. The big difference with using where is you can chain commands (of course, without calling first first.)

Let's have a look at when you try to find a record that isn't existing

>> User.find(2) # raises an exception
>> User.find_by_id(2) # nil
>> User.where(id: 2).first # nil

So here, it's obvious that when you use find to search for a record that isn't existing, you get an exception. That exception is ActiveRecord::RecordNotFound which renders a 404 on production environment.

Hope this helps!

UPDATE

Rails 4 uses the following syntax for find_by

>> User.find_by(id: 1)  # returns nil if there's no user with an id of 1
>> User.find_by!(id: 1) # raises ActiveRecord::RecordNotFound when no record is found
jvnill
  • 29,479
  • 4
  • 83
  • 86
  • 25
    You should note that all `find_by_*` methods are deprecrated in rails 4 in favor of `find_by(*: ...)` so here that would be be : `find_by(id: ...)` – pjam Mar 03 '13 at 13:04
  • 3
    wow I didn't know that. thanks! why isn't that mentioned here? http://edgeguides.rubyonrails.org/4_0_release_notes.html – jvnill Mar 03 '13 at 13:15
  • 2
    @pjam All dynamic methods except for find_by_... and find_by_...! are deprecated. https://edgeguides.rubyonrails.org/4_0_release_notes.html#active-record-deprecations – Jaffar Hussain Jan 04 '20 at 23:58
5

find => This return single record if the given primary_key(id) exists in the system otherwise in will give an error.

Model.find(required_id_value)

find_by => This will return single record depends on the given attribute, and if the value of the attribute is not exist in the DB it will return nil.

Model.find_by_name("your name")

name here is the attribute and it must be exist in your Modal.

where => This will return an active record relation with zero or more records you need to use first to return only one record or nil in case zero records return.

Model.where(id: id_value).first
Alanoud Just
  • 317
  • 3
  • 5
  • **Record.find(0)** raises `ActiveRecord::RecordNotFound: Couldn't find Record with 'id'=0` **Record.find_by(id: 0)** returns `nil` Record.find_by_id(0) also returns nil although it is deprecated in later versions of rails. **Record.where(id: 0)** returns an empty array – Hanmaslah Jan 04 '17 at 14:29
1

find => this is used to find row by id. This will return single record.

YourModel.find(2)
Address.find(1)

find_by => this is used to get row by any attributes of record. This will return first matching record if condition matches.

YourModel.find_by_attrname("value")
Address.find_by_street_name_and_city("Andheri", "Newyork")
Addess.find_by_id(4)

where => this is used get active records based on conditions to return active record relation (i.e.) may be zero or more records.

YourModel.where(:attrname => "something")
Address.where(:city => "Newyork")
Rahul Tapali
  • 9,887
  • 7
  • 31
  • 44
0

Simple to me....

'Find' returns single object to you as a result but 'Where' returns Array to you so you need to add .each to fetch each object from that array.

Bilal A.Awan
  • 290
  • 3
  • 7
0

Not big deal, but there is another difference between find and where when you try to retrieve 1+ records and then you need to update each record and you want to use the find_each, it gonna work over the where method because the result of the where query is a ActiveRecord::Relation. But if you try to use find_each over the result with the find, you gonna have an error.

Profile.find([1, 2, 3]).find_each { |e| puts e.id }
=> NoMethodError (undefined method `find_each' for 
 <Array:0x0000555e923d3f38>)


Profile.where(id: [1, 2, 3]).find_each { |e| puts e.id }
=> 1
=> 2
=> 3