find find_by whereメソッドの違いについて

レコードの検索時にfind find_by whereメソッドを使用していますが、
なんとなくフィーリングで使っていたので、それぞれの違いについてまとめてみました。
# findメソッド

findメソッドは、レコードの主キー(ID)を指定して、1件または複数のレコードを返します。重要なのは、findメソッドは与えられたIDに対応するレコードが存在することを前提としており、IDが存在しない場合は例外(ActiveRecord::RecordNotFound)が発生します。つまり、nilを返さずにエラーになります。

```ruby:sample.rb
#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が返されます。

```ruby:sample.rb

# メールアドレスを指定してユーザーのレコードを検索。
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つのオブジェクトではなく、**複数のまとまったオブジェクトが返ってくるのが特徴です**。検索結果が存在しない場合は空の配列を返し、１件でも結果があれば、配列の形で返します。

```ruby:sample.rb
# 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はプライマリーキー(主キー)を使用して１件のレコードを取得し、find_byは条件指定して見つかった最初の１件のレコードを返す(※)。いずれも単一のレコードを返さない。

一方で、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メソッドの解説でした。