web-dev-qa-db-ja.com

find vs find_by vs where

Railsは初めてです。レコードを見つける方法はたくさんあります。

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

そして、それらはすべてまったく同じSQLを生成するように見えます。また、複数のレコードを検索する場合も同じことが言えると思います。

  1. find_all_by_<columnname>(<columnvalue>)
  2. find(:all, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>)

どちらを使用するかについて、経験則または推奨事項はありますか?

115
Victor Ronin

ニーズに最も合ったものを使用してください。

findメソッドは通常、IDで行を取得するために使用されます。

Model.find(1)

指定した属性でアイテムが見つからない場合、findは例外をスローすることに注意してください。 where(以下で説明するように、属性が見つからない場合は空の配列を返す)を使用して、例外がスローされるのを防ぎます。

findの他の用途は、通常次のようなものに置き換えられます。

Model.all
Model.first

find_byは、列内の情報を検索するときにヘルパーとして使用され、命名規則を使用してそのようなものにマップします。たとえば、データベースにnameという名前の列がある場合、次の構文を使用します。

Model.find_by(name: "Bob")

.whereは、従来のヘルパーが実行しない場合にもう少し複雑なロジックを使用できるようにするキャッチオールであり、条件に一致する項目の配列(またはそうでない場合は空の配列)を返します。

90
John

whereはActiveRecord :: Relationを返します

次に、find_byの実装を見てみましょう。

def find_by
  where(*args).take
end

ご覧のとおりfind_bywhereと同じですが、1つのレコードのみを返します。このメソッドは、1つのレコードを取得するために使用する必要があり、whereは、いくつかの条件を持つすべてのレコードを取得するために使用する必要があります。

120
Mike Andrianov

findfind_byには違いがあり、findは見つからない場合はエラーを返し、find_byはnullを返します。

.where(email: some_params).firstではなくfind_by email: "haha"のようなメソッドを使用すると読みやすくなる場合があります。

31
Kasumi

Model.find

1-パラメータ:検索するオブジェクトのID。

2-見つかった場合:オブジェクトを返します(1つのオブジェクトのみ)。

3-見つからない場合:ActiveRecord::RecordNotFound例外を発生させます。

Model.find_by

1-パラメーター:キー/値

例:

User.find_by name: 'John', email: '[email protected]'

2-見つかった場合:オブジェクトを返します。

3-見つからない場合:nilを返します。

注:ActiveRecord::RecordNotFoundを上げる場合はfind_by!を使用します

Model.where

1-パラメーター:find_byと同じ

2-見つかった場合:パラメータに一致する1つ以上のレコードを含むActiveRecord::Relationを返します。

3-見つからない場合:空のActiveRecord::Relationを返します。

29
Hossam Khamis

Rails 4以降、次のことができます。

User.find_by(name: 'Bob')

Railsの同等のfind_by_name 3。

#where#findが十分でない場合は、#find_byを使用します。

17
Agis

受け入れられた答えは一般的にそれをすべてカバーしていますが、更新のような方法でモデルを使用する予定があり、単一のレコードを取得する場合に備えて、何かを追加したいと思います(誰がid知っている)、それからfind_byは行く方法です。なぜなら、レコードを取得し、配列に入れないからです

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

ただし、whereを使用する場合、直接更新することはできません

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)

このような場合、次のように指定する必要があります

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
Leonard Kakande

リストの両方の#2は廃止されています。ただし、find(params[:id])は引き続き使用できます。

一般的に、where()はほとんどの状況で機能します。

ここに素晴らしい投稿があります: http://m.onkey.org/active-record-query-interface

5
evanbikes

受け入れられた答えとは別に、以下も有効です

Model.find()はIDの配列を受け入れることができ、一致するすべてのレコードを返します。 Model.find_by_id(123)も配列を受け入れますが、配列に存在する最初のid値のみを処理します

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

モデルUserがあるとします

  1. User.find(id)

IDが指す行を返します。したがって、id = 1の場合、最初の行を返します。戻りタイプはユーザーオブジェクトになります。

  1. User.find_by(email:"[email protected]")

この場合、一致する属性または電子メールで最初の行を返します。戻り型は再びユーザーオブジェクトになります。

  1. User.where(project_id:1)

属性が一致するユーザーテーブル内のすべてのユーザーを返します。ここで返されるタイプは、Userオブジェクトのリストを含むActiveRecord :: Relationオブジェクトになります。

2

これまでに与えられた答えはすべてOKです。

ただし、興味深い違いの1つは、Model.findがIDで検索することです。見つかった場合、Modelオブジェクト(単一のレコードのみ)を返しますが、そうでない場合はActiveRecord::RecordNotFoundをスローします。

Model.find_byModel.findと非常に似ており、データベース内の任意の列または列のグループを検索できますが、検索に一致するレコードがない場合はnilを返します。

一方、Model.whereは、検索に一致するすべてのレコードを含む配列のようなModel::ActiveRecord_Relationオブジェクトを返します。レコードが見つからなかった場合、空のModel::ActiveRecord_Relationオブジェクトを返します。

これらがいつでも使用するものを決定するのに役立つことを願っています。

2
echelon