0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails / ActiveRecord】find / find_by / where の違いをざっくり理解する

Last updated at Posted at 2024-10-13

はじめに

お疲れ様です!
コンソールでデータ取得する際にfind, find_by, whereをなんとなく使用しており、使い分けについて説明することができなかったので、ざっくりまとめていきたいと思います:writing_hand:

qiita_find.png

先に3つの違いを一覧をまとめた上で、それぞれの特徴を書いていきます:sunglasses:

違いまとめ

メソッド     用途 返り値 条件に合わない場合
find 主キー(ID)で検索 単一のレコード 例外を発生 (ActiveRecord::RecordNotFound)
find_by 指定した条件で単一のレコードを検索 最初に見つかった単一のレコード nil を返す
where 指定した条件で複数のレコードを検索 ActiveRecord::Relation (配列状のオブジェクト) 空のリレーションを返す

find

  • 用途
    • 主キー(ID) で特定のレコードを1つだけ取得するために使用
  • 返り値
    • 見つかった場合   :そのレコードオブジェクトを返す
    • 見つからなかった場合:例外(ActiveRecord::RecordNotFound) が発生
  • 特徴
    • 主キー(ID)で検索するため、検索速度が速い
    • 存在しないIDを検索すると、エラーが発生

【ケース1】 主キーに対応するものを返す

pry(main)> User.find(1)

=> #<User:0x0000ffff98af47c0
 id: 1,
 email: "test-user-1@example.com",
 age: 28,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>

【ケース2】 主キーに対応するものがない場合は、エラーが発生

pry(main)> User.find(12345)

ActiveRecord::RecordNotFound: Couldn't find User with 'id'=12345

【ケース3】 主キーに配列を渡した場合は、マッチするレコードを全て含む配列を返す

pry(main)> User.find([1, 2])

=> [#<User:0x0000ffff98a4d4c0
 id: 1,
 email: "test-user-1@example.com",
 age: 28,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>,
 #<User:0x0000ffff98a4d3f8
 id: 2,
 email: "test-user-2@example.com",
 age: 28,
 created_at: Tue, 27 Aug 2024 18:54:35.492450000 JST +09:00,
 updated_at: Tue, 27 Aug 2024 18:57:11.529007000 JST +09:00>]

find_by

  • 用途
    • 任意のカラム に対して1つのレコードを取得するために使用
    • 複数の条件で検索する場合にも使用可能
  • 返り値
    • 見つかった場合   :最初に見つかったレコードオブジェクトを返す
    • 見つからなかった場合:nilを返す
  • 特徴
    • 一件だけレコードを取得したい場合に便利
    • 例外処理が不要な場合に使いやすい

【ケース1】 主キー以外で検索する

pry(main)> User.find_by(email: "test-user-1@example.com")

=> #<User:0x0000ffff98af47c0
 id: 1,
 email: "test-user-1@example.com",
 age: 28
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>

【ケース2】 複数条件を指定して検索する

pry(main)> User.find_by(email: "test-user-1@example.com", age: 28)

=> #<User:0x0000ffff98af47c0
 id: 1,
 email: "test-user-1@example.com",
 age: 28,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>

【ケース3】 条件に合わない場合はnilを返す

pry(main)> User.find_by(email: "test-user-12345@example.com")

=> nil

【ケース4】 複数条件指定した場合に、1つでも合わない場合はnilを返す

pry(main)> User.find_by(email: "test-user-1@example.com", age: 100)

=> nil

where

  • 用途
    • 複数のレコードを取得するために使用
    • 検索結果に対して追加のクエリやソートなどを行いたいときにも有用
  • 返り値
    • 見つかった場合   :ActiveRecord::Relationオブジェクトを返す
    • 見つからなかった場合:空のリレーションを返す
  • 特徴
    • ActiveRecord::Relationを返すため、メソッドチェインを使用可能
    • クエリの実行は遅延される(実際にデータが必要になるまでデータベースへの問い合わせを行わない)ので、複数の条件を組み合わせても効率的

【ケース1】 指定する条件のレコードを全て返す(ActiveRecord::Relationを返している)

pry(main)> User.where(age: 28)

=> [#<User:0x0000ffff98a4d4c0
 id: 1,
 email: "test-user-1@example.com",
 age: 28,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>,
 #<User:0x0000ffff98a4d3f8
 id: 2,
 email: "test-user-2@example.com",
 age: 28,
 created_at: Tue, 27 Aug 2024 18:54:35.492450000 JST +09:00,
 updated_at: Tue, 27 Aug 2024 18:57:11.529007000 JST +09:00>]


pry(main)> User.where(age: 28).class

=> User::ActiveRecord_Relation

【ケース2】 条件に合わない場合は空のリレーションを返す

pry(main)> User.find_by(email: "test-user-12345@example.com")

=> nil


pry(main)> User.find_by(email: "test-user-12345@example.com").class

=> User::ActiveRecord_Relation

【ケース3】 NOT条件(条件に一致しないものを返す)

pry(main)> User.where.not(age: 28)

=> [#<User:0x0000ffff98af47c0
 id: 3,
 email: "test-user-3@example.com",
 age: 40,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>]

【ケース4】 OR条件(複数条件のうちいずれかを満たすものを返す)

pry(main)> User.where(email: "test-user-1@example.com").or(User.where(age: 40))

=> [#<User:0x0000ffff98a4d4c0
 id: 1,
 email: "test-user-1@example.com",
 age: 28,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>,
#<User:0x0000ffff98af47c0
 id: 3,
 email: "test-user-3@example.com",
 age: 40,
 created_at: Mon, 26 Aug 2024 13:33:47.008672000 JST +09:00,
 updated_at: Thu, 10 Oct 2024 20:01:39.364167000 JST +09:00>]

補足

以下の説明が分かりやすかったので引用(引用元の記事

find

find は、特定のレコードを取得するためのメソッドなんや。
指定したIDに欲しい情報が入っていることを知っているから使うことになる。
情報が入っているはずで取得したのに、それが無かったから例外になるよな:thinking:

find_by

find_by は、条件を指定した検索メソッドなんやけど、検索結果があるかないかは検索してみないと分からん。
やから結果がないことはあり得ることで、例外ではない:ok_hand:
検索結果が無かったから結果通りnilを返す。

where

where は、find_by と同様に検索メソッドになる。
違いは、検索にマッチするすべてのレコードを取得できるということやな。
これも検索結果があるかないかは、検索してみないとわからないから、結果がないことは例外ではないな:thumbsup_tone2:
検索結果が0件だから、0件の配列を返す。

終わりに

記事にまとめることで3つの違いについて理解を深めることができました!
調べていくうちに理解できていない部分なども新たに発見することができましたので、そちらについても調べて記事にできたらなと思います!
調べたことを自分用にNotionにメモって終わっているものが結構あるので、人に説明できるレベルにするためにも月に1回は記事でアウトプットできるように個人学習頑張りたいと思います:sunglasses:
最後まで読んでいただき、ありがとうございました:four_leaf_clover:

参考記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?