find vs find_by vs where


127

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

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

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

回答:


103

ニーズに最も合うと思う方を使用してください。

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

Model.find(1)

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

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

Model.all
Model.first

find_byは、列内の情報を検索するときにヘルパーとして使用され、命名規則を使用してそれに対応します。たとえばname、データベースで名前が付けられた列がある場合、次の構文を使用します。

Model.find_by(name: "Bob")

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


62
find_byは非推奨ではありませんが、構文が少し変更されています。からfind_by_name("Bob")までfind_by(:name, "Bob")
Brian Morearty 14年

61
@BrianMorearty私はあなたが意味したと信じていますfind_by(name: "Bob")
MCB

1
@BrianMorearty find_by_...廃止予定の証拠を見つけることができませんでした。ソースがありますか?それはそうですfind_byし、find_by_...両方まだレール4でサポートされています
デニス・

4
@デニス、あなたはそれが非推奨ではないことは正しいです、そしてそれは私が言ったことです。しかし、「構文は少し変更されています」と言ったときは、もっと明確だったかもしれません。私が言ったのは、「しかし、新しい構文も利用できるようになった」新しい構文については、MCBの修正を参照してください。
Brian Morearty 2014年

3
これは、rails 4.0リリースで言及されている「find_by _...とfind_by _...を除くすべての動的メソッドは非推奨です」edgeguides.rubyonrails.org/…の
Mukesh Singh Rathaur

131

ここで ActiveRecord :: Relationを返します

次に、find_by実装を確認します。

def find_by
  where(*args).take
end

あなたが見ることができるようにfind_byは同じであるところが、それは1つのレコードだけを返します。この方法では、1つのレコードを取得して使用してくださいどこいくつかの条件にすべてのレコードを取得するために使用すべきです。


1
find_byはオブジェクトを返しますが、whereはコレクションを返します。
Kick Buttowski 2017年

クエリ値が範囲外の場合は、 nil find_byをレスキュー::RangeErrorwhere(*args)て返します。
ファングシング

34

Model.find

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

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

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

Model.find_by

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

例:

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

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

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

注:ActiveRecord::RecordNotFound使用を増やしたい場合find_by!

Model.where

1-パラメータ:同じ find_by

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

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


31

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

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


17

Rails 4以降は次のことができます:

User.find_by(name: 'Bob')

これはfind_by_nameRails 3で同等です。

使用#whereするとき#find#find_by十分ではありません。


2
アギス、私はあなたに同意しますが、私たちはインターネットを使用してfind_by、なぜ私たちが使用すべきか、そうでないべきかを探してきましたfind_by_<column_name>。誰かに答えるにはそれが必要です。
2014年

Agis、find_by_nameRails 4 で使用すべきではないというあなたの主張を裏付ける情報源はありますか?私の知る限り、これは非推奨ではありません
Dennis

それを行う簡単な方法はありますが、名前にワイルドカードが含まれているため、次のようになりますfind_by(name: "Rob*")
Batman

1
@Dennis両方を使用することが可能で、有効です。APIはより直感的なIMHOであるため、新しい構文を好みます。それが私が自分でデザインする方法です:)
Agis

8

受け入れ答えは、一般的にそれをすべてカバーしますが、私はちょうどあなたが更新のような方法で、モデルで動作するように計画している、とあなたは(その単一のレコード取得している包み、何かを追加したいのですが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

まさに私が探していたもの
Paul Brunache 2015年

2
@kit = Kit.where(number: "3456")。first-これにより、直接更新できるようになり、非推奨になったため安全です
Paul Brunache 2015年

6

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

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

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


3

これまでの回答はすべてOKです。

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

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

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

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


3

モデルがあるとしましょう User

  1. User.find(id)

主キー= idである行を返します。戻り値の型はUserオブジェクトになります。

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

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

注:- User.find_by(email: "abc@xyz.com")に似ていますUser.find_by_email("abc@xyz.com")

  1. User.where(project_id:1)

属性が一致するユーザーテーブル内のすべてのユーザーを返します。

ここでは、戻り値の型はActiveRecord::Relationオブジェクトになります。ActiveRecord::RelationクラスにはRubyのEnumerableモジュールが含まれているため、配列のようなオブジェクトのオブジェクトを使用してトラバースできます。


0

オープンソーステクノロジを使用する上での最良の部分は、その長さと幅を検査できることです。 このリンクをチェックアウト

find_by〜>指定された条件に一致する最初のレコードを検索します。暗黙の順序付けはないため、順序が重要な場合は、自分で指定する必要があります。レコードが見つからない場合は、nilを返します。

find〜>指定された条件に一致する最初のレコードを検索しますが、レコードが見つからない場合は例外が発生しますが、意図的に行われます。

上記のリンクをチェックアウトしてください。次の2つの機能のすべての説明と使用例があります。


-5

個人的に使用をお勧めします

where(< columnname> => < columnvalue>)

1
これは質問に答えるかもしれません。しかし、受け入れられた答えの代わりに、あなたのアプローチを使用することの長所と短所を説明してみてください。
Vivek Kumar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.