findとfind_byの違いを初心者がまとめてみました。

この記事では**find**と**find_by**の違いについて分かりやすく伝わるように書いてみようと思います。
わかりにくいところがあれば参考記事も確認して、しっかりと理解していただければ幸いです。

#findとは
- **id**を検索キーとして、取得したいモデルから特定のデータを取得する方法
- findを使用する場合には、**id**以外では検索できない
- 要するに、取得したいデータの**id**が分かっている場合に使用するといい
- 検索の仕方は モデル名.find(id)　例：User.find(1)

####使用方法
例えばUserモデルにあるtaroさんのデータが欲しいとします。
その場合、findで検索するとなると　**id**　で検索してあげる必要があります。

Userモデル

| id | name | age |
|:--:|:-:|:-:|
|  1 |taro  |23 |
|  2|jiro   |20 |
|  3|sabu   |18 |

```
User.find(1)
→ユーザモデル(User)から、idが1(find.(1))のものを取得
```

こうすればtaroさんのインスタンス（すぐに使用できるデータ）が取得できます。
挙動は

```
2.5.3 :001 > user1 = User.find(1)
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<User id: 1, name: "taro", age: 23, created_at: "2020-03-31 02:27:04", updated_at: "2020-03-31 02:27:11"> 
```
このように流れてきます。
そしてこのようにすればidが1(taroさん)のageだけを取り出すことができます。

```
2.5.3 :002 > user1.age
 => "23" 
```

#find_byとは
- **id以外**のカラムを指定して、1つのデータを取得する方法(idでも検索可能)
- id以外の値が分かっているときに使用できる
- 複数の条件指定が可能
- 値として返ってくるのは、条件にヒットした最初の1件のみ
- 検索の方法は モデル名.find_by(カラム名: 値)　例：User.find_by(name: "taro") 

####使用方法
例えばUserモデルにあるjiroさんのデータが欲しいとします。
その場合、find_byで検索するとなると　**カラム名: 値**　で検索して上げる必要があります。

Userモデル

| id | name | age |
|:--:|:-:|:-:|
|  1 |taro  |23 |
|  2|jiro   |20 |
|  3|sabu   |18 |

```
User.find_by(name: 'jiro')
→ユーザモデル（User）から名前がjiro（name: 'jiro'）のデータを取得
```
と言う風になります。こうすればnameがjiroさんのデータを取り出すことができます。
挙動は

```
2.5.3 :001 > user = User.find_by(name: 'jiro')
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "jiro"], ["LIMIT", 1]]
 => #<User id: 2, name: "jiro", age: 20, created_at: "2020-03-31 02:27:26", updated_at: "2020-03-31 02:27:26"> 
```

このように流れてきます。そして、find_byでは　**値として返ってくるのは条件にヒットした最初の１件のみ**　が返ってきます。
どういうことかと言うと
年齢が20才の2人がいたとします。

Userモデル

| id | name | age |
|:--:|:-:|:-:|
|  1 |taro  |23 |
|  2|jiro   |20 |
|  3|sabu   |20 |

このような場合にfind_byを使用して　User.find_by(age: 20)　としても sabuさんのデータは取れません。

```
2.5.3 :001 > user = User.find_by(age: 20)                                                                                                                         
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."age" = ? LIMIT ?  [["age", 20], ["LIMIT", 1]]
 => #<User id: 2, name: "jiro", age: 20, created_at: "2020-03-31 02:27:26", updated_at: "2020-03-31 02:27:26"> 
```

idを順にみていくので、ageが20である最初のデータはidが2のjiroさんになってしまいます。なので、sabuさんのデータを取ろうと思うと、別の条件でとるしかないということになります。

また、　**複数の条件指定が可能**　というのはこのようにします。
例えば、兵庫県出身の20才のデータを取得したい時には

Userモデル

| id | name | age |pref
|:--:|:-:|:-:|:-:|
|  1 |taro  |23 |大阪|
|  2|jiro   |20 |東京|
|  3|sabu   |20 |兵庫|

```
2.5.3 :002 > user = User.find_by(age: 20, pref: '兵庫')                                                                                                           
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."pref" = ? AND "users"."pref" = ? LIMIT ?  [["age", 20], ["pref", "兵庫"], ["LIMIT", 1]]
 => #<User id: 3, name: "sabu", age: 20, pref: "兵庫", created_at: "2020-03-31 02:27:35", updated_at: "2020-03-31 03:49:24"> 
```

このようにすれば、複数条件に当てはまる最初のデータが返ってきます。
また、find_byで取り出したデータもインスタンスなので、このようにすれば指定のカラムのデータを取得することができます。

```
2.5.3 :003 > user.name
 => "sabu" 
```


#データが見つからなかった時の違い
###findの場合
例えば下のようなUserモデルがあったとして、間違えて　User.find（4）と存在しないidを指定したとします。
Userモデル

| id | name | age |
|:--:|:-:|:-:|
|  1 |taro  |23 |
|  2|jiro   |20 |
|  3|sabu   |20 |

```
2.5.3 :004 > user = User.find(4)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 4], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):4
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=4)
```
このように返ってきます。

```
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=4)
```
ここでは、idが4のデータは見つかりませんでした。といった **エラー**　が返ってきます。エラーが返ってくるとエラー画面が表示され、動かなくなってしまいます。


####find_byの場合
同じUserモデルを使用して　間違えて User.find_by(name: 'gonta') と存在しないnameを指定したとします。

```
2.5.3 :005 > user = User.find_by(name: 'gonta')
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "gonta"], ["LIMIT", 1]]
 => nil 
```
このように　**エラー**　ではなく　**nil**　が返ってきます。
nilが返ってくるということは、エラー画面は表示されずに処理が進みます。

####要するにどういうことか
例えばこのようなfindを使ったif文を書いたとします。

```
user = User.find(4)

if user
 puts 'ユーザが見つかりました。'
else
 put 'ユーザが見つかりませんでした。'
end
```
この場合、userには何も代入されておらず、エラー画面が表示されて動きません。
しかし、find_byを使ったif文にすると

```
user = User.find_by(id: 4)

if user
 puts 'ユーザが見つかりました。'
else
 put 'ユーザが見つかりませんでした。'
end
```
この場合には、userにはnilが代入されていることになり、if文のelseが適応となって　ユーザが見つかりませんでした　と出力されることになります。


#まとめ
findとfind_byの違いってサービスを開発してみるまでは、正直意味が分かりませんでした。
違いをしっかり理解して使っていくようにしましょう。
最後まで読んでいただきありがとうございました。:relaxed:

#参考にした記事
[find、find_by、whereの違い](https://qiita.com/tsuchinoko_run/items/f3926caaec461cfa1ca3)
[【Rails初心者必見！】ひたすら丁寧にデータ取得を説明(find, where)](https://qiita.com/mr-myself/items/cfb936dcf63d2c44d2f5)
大変参考になりました。ありがとうございます。