Find vs find_by vs where

I am new to rails. I see that there are many ways to find a record:

  • find_by_<columnname>(<columnvalue>)
  • find(:first, :conditions => { <columnname> => <columnvalue> }
  • where(<columnname> => <columnvalue>).first

And it looks like they all end up generating exactly the same SQL. In addition, I believe the same is true for finding multiple entries:

  • find_all_by_<columnname>(<columnvalue>)
  • find(:all, :conditions => { <columnname> => <columnvalue> }
  • where(<columnname> => <columnvalue>)

Is there a rule of thumb or recommendations for use?

+116
ruby-on-rails rails-activerecord
Jun 22 '12 at 17:58
source share
11 answers

Use the one that suits you best.

The find method is usually used to retrieve a string by ID:

 Model.find(1) 

It is worth noting that find will throw an exception if the item is not found by the attribute you specified. Use where (as described below, which will return an empty array if the attribute is not found) to avoid throwing an exception.

Other use cases for find are usually replaced by such things:

 Model.all Model.first 

find_by used as an find_by in finding information in a column and is mapped to such naming conventions. For example, if your database has a column named name , you should use the following syntax:

 Model.find_by(name: "Bob") 

.where is another .where which allows you to use a little more complex logic when ordinary helpers do not, and returns an array of elements matching your conditions (or an empty array otherwise).

+91
Jun 22 '12 at 18:17
source share

where returns ActiveRecord :: Relation

Now take a look at the find_by implementation:

 def find_by where(*args).take end 

As you can see, find_by matches where , but returns only one record. This method should be used to get 1 record and where should be used to get all records with some conditions.

+122
Apr 03 '14 at 9:49
source share

There is a difference between find and find_by in that find will return an error if not found, whereas find_by will return null.

This is sometimes easier to read if you have a method like find_by email: "haha" and not .where(email: some_params).first .

+31
Jun 22 '12 at 18:20
source share

Model.find

1- Parameter: identifier of the found object.

2- If found: It returns an object (only one object).

3- If not found: an ActiveRecord::RecordNotFound exception is ActiveRecord::RecordNotFound .

Model.find_by

1- Parameter: key / value

Example:

 User.find_by name: 'John', email: 'john@doe.com' 

2- If found: It returns an object.

3- If not found: returns nil .

Note: If you want to raise ActiveRecord::RecordNotFound , use find_by!

Model.where

1- Parameter: same as find_by

2- If found: It returns ActiveRecord::Relation containing one or more records matching the parameters.

3- If not found: it returns Empty ActiveRecord::Relation .

+29
Dec 27 '16 at 0:32
source share

With Rails 4 you can do:

 User.find_by(name: 'Bob') 

which is equivalent to find_by_name in Rails 3.

Use #where when #find and #find_by not enough.

+17
Jun 22 '14 at 13:51 on
source share

The accepted answer usually covers all of this, but I would like to add something, just you can plan to work with the model in such a way as updating, and you retrieve one record (whose id you do not know), then find_by is the way to go, because it retrieves the record and does not put it in an array

 irb(main):037:0> @kit = Kit.find_by(number: "3456") Kit Load (0.9ms) SELECT "kits".* FROM "kits" WHERE "kits"."number" = '3456' LIMIT 1 => #<Kit id: 1, number: "3456", created_at: "2015-05-12 06:10:56", updated_at: "2015-05-12 06:10:56", job_id: nil> irb(main):038:0> @kit.update(job_id: 2) (0.2ms) BEGIN Kit Exists (0.4ms) SELECT 1 AS one FROM "kits" WHERE ("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.5ms) UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE "kits"."id" = 1 [["job_id", 2], ["updated_at", Tue, 12 May 2015 07:16:58 UTC +00:00]] (0.6ms) COMMIT => true 

but if you use where , you cannot update it directly

 irb(main):039:0> @kit = Kit.where(number: "3456") Kit Load (1.2ms) SELECT "kits".* FROM "kits" WHERE "kits"."number" = '3456' => #<ActiveRecord::Relation [#<Kit id: 1, number: "3456", created_at: "2015-05-12 06:10:56", updated_at: "2015-05-12 07:16:58", job_id: 2>]> irb(main):040:0> @kit.update(job_id: 3) ArgumentError: wrong number of arguments (1 for 2) 

in that case you would need to specify it like this:

 irb(main):043:0> @kit[0].update(job_id: 3) (0.2ms) BEGIN Kit Exists (0.6ms) SELECT 1 AS one FROM "kits" WHERE ("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.6ms) UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE "kits"."id" = 1 [["job_id", 3], ["updated_at", Tue, 12 May 2015 07:28:04 UTC +00:00]] (0.5ms) COMMIT => true 
+9
May 12 '15 at 7:36
source share

Both # 2 on your listings are out of date. You can still use find(params[:id]) .

Typically, where() works in most situations.

Here is a great post: http://m.onkey.org/active-record-query-interface

+5
Jun 22 '12 at 18:15
source share

In addition to the accepted answer, the following is also true.

Model.find() can take an array of identifiers and return all records that match. Model.find_by_id(123) also takes an array, but only processes the first id value present in the array

 Model.find([1,2,3]) Model.find_by_id([1,2,3]) 
+5
Aug 06 '15 at 10:46
source share

Suppose I have a user model

  1. User.find(id)

Returns the string indicated by the identifier. Suppose that if id = 1, it will return the first row. The return type will be a custom object.

  1. User.find_by(email:"abc@xyz.com")

In this case, returns the first row with the corresponding attribute or email address. The return type will again be a User object.

  1. User.where(project_id:1)

Returns all users in the user table where the attribute matches. The return type here is an ActiveRecord :: Relation object containing a list of User objects.

+2
Oct 14 '16 at 9:07
source share

The answers given so far are all right.

However, one interesting difference is that Model.find searches by id; if found, it returns a Model object (only one record), but in ActiveRecord::RecordNotFound case ActiveRecord::RecordNotFound ActiveRecord::RecordNotFound .

Model.find_by very similar to Model.find and allows you to search for any column or group of columns in your database, but returns nil if no records match the search.

Model.where other hand, Model.where returns a Model::ActiveRecord_Relation object that looks like an array containing all the records matching the query . If the record is not found, an empty Model::ActiveRecord_Relation object is returned.

I hope this helps you decide which one to use at any given time.

+2
Jul 12 '19 at 16:23
source share

I personally recommend using

 where(< columnname> => < columnvalue>) 
-four
May 03 '17 at 11:41 a.m.
source share



All Articles