find vs find_by vs where

人走茶凉 提交于 2019-11-27 02:51:54

Use whichever one you feel suits your needs best.

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

Model.find(1)

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

Other uses of find are usually replaced with things like this:

Model.all
Model.first

find_by is used as a helper when you're searching for information within a column, and it maps to such with naming conventions. For instance, if you have a column named name in your database, you'd use the following syntax:

Model.find_by(name: "Bob")

.where is more of a catch all that lets you use a bit more complex logic for when the conventional helpers won't do, and it returns an array of items that match your conditions (or an empty array otherwise).

Mike Andrianov

where returns ActiveRecord::Relation

Now take a look at find_by implementation:

def find_by
  where(*args).take
end

As you can see find_by is the same as where but it returns only one record. This method should be used for getting 1 record and where should be used for getting all records with some conditions.

Kasumi

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.

Sometimes it is easier to read if you have a method like find_by email: "haha", as opposed to .where(email: some_params).first.

Model.find

1- Parameter: ID of the object to find.

2- If found: It returns the object (One object only).

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

Model.find_by

1- Parameter: key/value

Example:

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

2- If found: It returns the object.

3- If not found: returns nil.

Note: If you want it 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 return an Empty ActiveRecord::Relation.

Since Rails 4 you can do:

User.find_by(name: 'Bob')

which is the equivalent find_by_name in Rails 3.

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

The accepted answer generally covers it all, but I'd like to add something, just incase you are planning to work with the model in a way like updating, and you are retrieving a single 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 then you can not 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 such a case you would have 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

Both #2s in your lists are being deprecated. You can still use find(params[:id]) though.

Generally, where() works in most situations.

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

Saumya Mehta

Apart from accepted answer, following is also valid

Model.find() can accept array of ids, and will return all records which matches. Model.find_by_id(123) also accept array but will only process first id value present in array

Model.find([1,2,3])
Model.find_by_id([1,2,3])

Suppose I have a model User

  1. User.find(id)

Returns a row pointed by the id. So suppose, if id = 1, then it will return first row. Return type will be User object.

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

Returns first row with matching attribute or email in this case. Return type will be User object again.

  1. User.where(project_id:1)

Returns all users in users table where attribute matches. Here return type will be ActiveRecord::Relation object containing list of User objects.

The answers given so far are all OK.

However, one interesting difference is that Model.find searches by id; if found, it returns a Model object (just a single record) but throws an ActiveRecord::RecordNotFound otherwise.

Model.find_by is very similar to Model.find and lets you search any column or group of columns in your database but it returns nil if no record matches the search.

Model.where on the other hand returns a Model::ActiveRecord_Relation object which is just like an array containing all the records that match the search. If no record was found, it returns an empty Model::ActiveRecord_Relation object.

I hope these would help you in deciding which to use at any point in time.

Prateek Alakh

I will personally recommend using

where(< columnname> => < columnvalue>)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!