レコードの検索時にfind find_by whereメソッドを使用していますが、
なんとなくフィーリングで使っていたので、それぞれの違いについてまとめてみました。
findメソッド
findメソッドは、レコードの主キー(ID)を指定して、1件または複数のレコードを返します。重要なのは、findメソッドは与えられたIDに対応するレコードが存在することを前提としており、IDが存在しない場合は例外(ActiveRecord::RecordNotFound)が発生します。つまり、nilを返さずにエラーになります。
#IDが1のユーザーを取得
user = User.find(1)
User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
`=> #<User id: 1, email: "test_user0@gmail.com", created_at: "2024-08-22 20:12:19.678646000 +0900", updated_at: "2024-08-25 20:20:16.811749000 +0900">`
# 存在しないIDで検索。例外が発生(ActiveRecord::RecordNotFound)
user = User.find(999999999999)
User Load (8.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 999999999999 LIMIT 1
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=999999999999
from /usr/local/bundle/gems/activerecord-6.1.7.4/lib/active_record/core.rb:353:in `find'
特徴
・主キー(ID)を使ってレコードを取得するので、
基本的には1件のレコードを取得するためのメソッド
・結果が存在しない場合は、nilを返さずに例外が発生する
・配列で複数のIDを指定することで、複数のレコードを一度に取得できる
find_byメソッド
find_byメソッドは、ID以外の任意のカラムに基づいて検索する。条件に合致する最初のレコードを返す。該当するレコードが存在しない場合は例外は発生せずに、nilが返されます。
# メールアドレスを指定してユーザーのレコードを検索。
user = User.find_by(email: "test_user0@email.com")
User Load (2.2ms) SELECT * FROM users WHERE users.email = 'test_user0@gmail.com' LIMIT 1
=> <User id: 1, email: "test_user0@email.com", created_at: "2020-08-22 20:12:19.678646000 +0900", updated_at: "2020-08-25 20:20:16.811749000 +0900">
# 存在しないメールアドレスで検索。
user = User.find_by(email: "**********")
User Load (7.3ms) SELECT `users`.* FROM `users` WHERE `users`.`email` = '**********' LIMIT 1
=> nil
特徴
・任意のカラムを使って検索することができる。emailやnameなどの特定の属性に対して検索することができるので、柔軟な検索が可能
・複数の条件に合致する場合でも、最初に見つかったレコード1件のみを返す(複数のレコードを取得したい場合はwhereメソッドを使用する)
・該当するレコードがない場合はnilを返すそのため、存在しない可能性がある処理に対しても柔軟に対応できる(userがnilの場合の処理を書くなど)
whereメソッド
whereメソッドは、テーブル内の条件に一致したレコードを配列の形で返します。1つのオブジェクトではなく、複数のまとまったオブジェクトが返ってくるのが特徴です。検索結果が存在しない場合は空の配列を返し、1件でも結果があれば、配列の形で返します。
# USERのIDが5以上のユーザーを検索
User.where("id > ?", 5)
=> User Load (9.0ms) SELECT `users`.* FROM `users` WHERE (id > 5)
[#<User id: 6, email: "test_user5@email.com", created_at: "2020-08-22 20:12:20.869230000 +0900", updated_at: "2020-08-22 20:12:20.869230000 +0900">,
#<User id: 7, email: "test_user6@email.com", created_at: "2020-08-22 20:12:21.117923000 +0900", updated_at: "2020-08-22 20:12:21.117923000 +0900">,
#<User id: 8, email: "test_user7@email.com", created_at: "2020-08-22 20:12:21.350857000 +0900", updated_at: "2020-08-22 20:12:21.350857000 +0900">
# 複数の条件を指定してレコードを検索することも可能。
User.where("id > ? AND gender = ?", 5, 'male')
#<User id: 28, email: "tester012@email.com", created_at: "2020-09-17 21:58:40.152471000 +0900", updated_at: "2024-09-17 21:58:52.186041000 +0900",
#<User id: 30, email: "tester013@email.com", created_at: "2020-09-17 21:29:03.588729000 +0900", updated_at: "2024-09-17 21:29:19.207693000 +0900"
# 他のActiveRecordのメソッド 例のようにorderメソッドと組み合わせて使用することもできる。
User.where("id > ?", 5).order("created_at DESC")
=> User Load (1.3ms) SELECT `users`.* FROM `users` WHERE (id > 5) ORDER BY created_at DESC
[#<User id: 38, email: "tester012@gmail.com", created_at: "2024-09-17 21:58:40.152471000 +0900", updated_at: "2024-09-17 21:58:52.186041000 +0900">,
#<User id: 37, email: "test@email.com", created_at: "2024-09-17 21:29:03.588729000 +0900", updated_at: "2024-09-17 21:29:19.207693000 +0900">
# 結果が存在しない場合は、例外は発生せず、空のリレーション(`ActiveRecord::Relation`オブジェクト)を返します。
User.where(age: 200)
=> User Load (9.2ms) SELECT `users`.* FROM `users` WHERE `users`.`age` = 200
[]
特徴
・whereメソッドは、複数のレコードを取得する際に使用する。検索結果は、ActiveRecord:Relationオブジェクトという配列のような形で返ってくる。
・検索結果が存在しない場合は、例外処理は発生せずに、空のリレーションを返す。このオブジェクトは配列のように扱えるため、結果が空の場合は[]
と表示されるが、実際に返されているのはActiveRecord::Relation
となる。
・findやfind_byとの大きな違いは、前述の通り、複数のレコードを取得できること。findはプライマリーキー(主キー)を使用して1件のレコードを取得し、find_byは条件指定して見つかった最初の1件のレコードを返す(※)。いずれも単一のレコードを返さない。
一方で、whereメソッドは、条件に合致する複数のレコードを取得することができる。そのため、アプリケーションの検索機能の実装で頻繁に使用される。
※ find_byは複数の条件を指定できますが、最初に見つかった1件のレコードのみを返します。そのため、複数のレコードを取得することはできません。
find find_by whereの違い
メソッド | 主キー検索 | 条件検索 | 結果がない場合 | 戻り値 |
---|---|---|---|---|
find | 主キーのみ | 不可 | 例外が発生 | 1件または複数のレコード |
find_by | 可能 | 可能 | nilを返す | 1件のレコード |
wherer | 不可 | 可能 | 空のリレーション | ActiveRecord::Relationオブジェクト(複数のレコード) |
find find_by whereメソッドについて検索方法、検索結果が存在しない場合、
メソッドの返り値をおおざっぱにまとめると上記の表の通りです。
使い分けとしては、だいたい下記のシチュエーションで使用することになると思います。
find ・・・idの値が明確で、そのidのデータを取得したい場合
find_by ・・・ idの値が不明。id以外のカラムを検索条件としたい場合
where ・・・ id以外のカラムの検索条件で、複数の検索結果を取得したい場合
以上、find find_by whereメソッドの解説でした。