What is the difference between find(id) and find_by(id: id) in Rails
This minipost will explain in detail the difference between the two finders find(id)
and find_by(id: id)
. Both do the exact same thing when the record exists in the database. However, they handle differently the return values, when the record is not found in the database.
To demonstrate the difference, jump to your rails console in an existing rails application project where you can try the finders and see their behaviour. For this reason, let's say you have a project with a Model Post
, where you can run the rails console.
On your rails console try to get the id of the last record that was stored in the database by:
Post.all.last.id (8.1ms) SET @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 350 Post Load (1.7ms) SELECT `posts`.* FROM `posts` ORDER BY `posts`.`id` DESC LIMIT 1 => 1
And lets try both of the finders with an id that exists in the database.
Post.find(1) Post Load (2.5ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 1 LIMIT 1 => #<Post:0x00007f5d382ca000 id: 1, details: "", created_at: Tue, 29 Jan 2019 13:44:56 UTC +00:00, updated_at: Tue, 29 Jan 2019 13:44:56 UTC +00:00>
Post.find_by(id: 1) Post Load (2.5ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 1 LIMIT 1 => #<Post:0x000055d14a129c80 id: 1, details: "", created_at: Tue, 29 Jan 2019 13:44:56 UTC +00:00, updated_at: Tue, 29 Jan 2019 13:44:56 UTC +00:00>
Both of the finders, respond exactly the same when the record exists in the database. Given the fact that, the last record in our database has the id
of 1 let's try and see the behaviour of the finders on an id that does not exist in the database:
Post.find(2) Post Load (0.2ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 2 LIMIT 1 ActiveRecord::RecordNotFound: Couldn't find Post with 'id'=2 from /box/gems/activerecord-5.2.1.1/lib/active_record/core.rb:177:in `find'
Post.find_by(id: 2) Post Load (0.4ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 2 LIMIT 1 => nil
As you can see, the finder find(id)
raises ActiveRecord::RecordNotFound
exception when the record does not exist, whereas, the finder find_by(id: id)
returns nil
. Therefore, when you want to avoid catching exceptions you can use find_by(id: id)
.