Ruby on Rails

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).

Additional information: