はじめに
Railsでモデルの検索に使えるメソッドfind, find_by, where
の使い方や違いについて紹介します。
結論
find | find_by | where | |
---|---|---|---|
括弧の中に指定するものは? | id(複数可能) | 条件 | 条件 |
戻り値 | 条件に一致するデータ全て | 条件に一致する最初の1件だけ | 条件に一致するデータ全て |
戻り値の型 | モデルのインスタンス (結果が複数の場合は配列) | モデルのインスタンス |
ActiveRecord::Relation のインスタンス |
検索結果がない場合 | 例外発生 |
nil を返す |
空きのActiveRecord::Relation を返す |
動作確認
テストデータ
irb(main):015:0> Word.all
Word Load (4.5ms) SELECT `words`.* FROM `words`
=>
[#<Word:0x00007f21a3d7ed78
id: 1,
vocabulary: "詐欺",
pronunciation: "さぎ",
viewing: 10,
meaning: "相手をだますこと",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00>,
#<Word:0x00007f21a3d7e968
id: 2,
vocabulary: "鷺",
pronunciation: "さぎ",
viewing: 53,
meaning: "鳥の一種類",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.278526000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.278526000 UTC +00:00>,
#<Word:0x00007f21a3d7e800
id: 3,
vocabulary: "子供",
pronunciation: "こども",
viewing: 11,
meaning: "年のいかない幼い者",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00>,
#<Word:0x00007f21a3d7e698
id: 4,
vocabulary: "大人",
pronunciation: "おとな",
viewing: 20,
meaning: "成長して一人前になった人",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00>]
括弧の中に指定するものは?
find
モデルののIDを指定して検索する。IDは1個または複数を指定可能。
★1個指定したとき
irb(main):016:0> Word.find(1)
Word Load (2.5ms) SELECT `words`.* FROM `words` WHERE `words`.`id` = 1 LIMIT 1
=>
#<Word:0x00007f21a277bb20
id: 1,
vocabulary: "詐欺",
pronunciation: "さぎ",
viewing: 10,
meaning: "相手をだますこと",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00>
★複数指定したとき
irb(main):017:0> Word.find(1,2)
Word Load (1.1ms) SELECT `words`.* FROM `words` WHERE `words`.`id` IN (1, 2)
=>
[#<Word:0x00007f21a26b6c58
id: 1,
vocabulary: "詐欺",
pronunciation: "さぎ",
viewing: 10,
meaning: "相手をだますこと",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00>,
#<Word:0x00007f21a26b6b90
id: 2,
vocabulary: "鷺",
pronunciation: "さぎ",
viewing: 53,
meaning: "鳥の一種類",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.278526000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.278526000 UTC +00:00>]
★複数指定したときは配列でもOK
irb(main):021:0> Word.find([1,3,4])
Word Load (1.0ms) SELECT `words`.* FROM `words` WHERE `words`.`id` IN (1, 3, 4)
=>
[#<Word:0x00007f21a30829a8
id: 1,
vocabulary: "詐欺",
pronunciation: "さぎ",
viewing: 10,
meaning: "相手をだますこと",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00>,
#<Word:0x00007f21a30828b8
id: 3,
vocabulary: "子供",
pronunciation: "こども",
viewing: 11,
meaning: "年のいかない幼い者",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00>,
#<Word:0x00007f21a30827f0
id: 4,
vocabulary: "大人",
pronunciation: "おとな",
viewing: 20,
meaning: "成長して一人前になった人",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00>]
find_by
条件にモデルの属性: 値
の形を指定して検索する。
irb(main):024:0> Word.find_by(vocabulary: "鷺")
Word Load (1.2ms) SELECT `words`.* FROM `words` WHERE `words`.`vocabulary` = '鷺' LIMIT 1
=>
#<Word:0x00007f21a3da92d0
id: 2,
vocabulary: "鷺",
pronunciation: "さぎ",
viewing: 53,
meaning: "鳥の一種類",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.278526000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.278526000 UTC +00:00>
where
SQL文のwhere句に書くような感覚で条件指定して検索をする。
モデルの属性: 値
とかモデルの属性 > 値
みたいに
★例1
irb(main):031:0> Word.where(vocabulary: "子供")
Word Load (0.8ms) SELECT `words`.* FROM `words` WHERE `words`.`vocabulary` = '子供'
=>
[#<Word:0x00007f21a30dc8e0
id: 3,
vocabulary: "子供",
pronunciation: "こども",
viewing: 11,
meaning: "年のいかない幼い者",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00>]
★例2
irb(main):036:0> Word.where("id > 2")
Word Load (1.1ms) SELECT `words`.* FROM `words` WHERE (id > 2)
=>
[#<Word:0x00007f21a3d9ed30
id: 3,
vocabulary: "子供",
pronunciation: "こども",
viewing: 11,
meaning: "年のいかない幼い者",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00>,
#<Word:0x00007f21a3d9e740
id: 4,
vocabulary: "大人",
pronunciation: "おとな",
viewing: 20,
meaning: "成長して一人前になった人",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00>]
★例3(id=2以外を取得)
irb(main):039:0> Word.where("id <> 2")
Word Load (1.1ms) SELECT `words`.* FROM `words` WHERE (id <> 2)
=>
[#<Word:0x00007f21a3c45a10
id: 1,
vocabulary: "詐欺",
pronunciation: "さぎ",
viewing: 10,
meaning: "相手をだますこと",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00>,
#<Word:0x00007f21a3c458d0
id: 3,
vocabulary: "子供",
pronunciation: "こども",
viewing: 11,
meaning: "年のいかない幼い者",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.298938000 UTC +00:00>,
#<Word:0x00007f21a3c45808
id: 4,
vocabulary: "大人",
pronunciation: "おとな",
viewing: 20,
meaning: "成長して一人前になった人",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.321767000 UTC +00:00>]
戻り値
find
(「括弧の中に指定するものは?」と検証内容がかぶるため割愛します。)
find_by
irb(main):045:0> Word.find_by(pronunciation: "さぎ")
Word Load (8.4ms) SELECT `words`.* FROM `words` WHERE `words`.`pronunciation` = 'さぎ' LIMIT 1
=>
#<Word:0x00007f21a308b9b8
id: 1,
vocabulary: "詐欺",
pronunciation: "さぎ",
viewing: 10,
meaning: "相手をだますこと",
example: nil,
created_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00,
updated_at: Sun, 23 Jul 2023 04:25:33.251697000 UTC +00:00>
pronunciation: "さぎ"
は2件存在するが、最初の1件だけ返されました。
where
(「括弧の中に指定するものは?」と検証内容がかぶるため割愛します。)
戻り値の型
find
★結果が1件の場合、Wordのインスタンスを返す
irb(main):052:0> Word.find(4).class
Word Load (2.7ms) SELECT `words`.* FROM `words` WHERE `words`.`id` = 4 LIMIT 1
=> Word(id: integer, vocabulary: string, pronunciation: string, viewing: integer, meaning: text, example: text, created_at: datetime, updated_at: datetime)
★結果が複数の場合、配列を返す
irb(main):053:0> Word.find([2,4]).class
Word Load (1.4ms) SELECT `words`.* FROM `words` WHERE `words`.`id` IN (2, 4)
=> Array
★配列を返したとしても中身はWordのインスタンスの集合
irb(main):054:0> Word.find([2,4])[1].class
Word Load (2.7ms) SELECT `words`.* FROM `words` WHERE `words`.`id` IN (2, 4)
=> Word(id: integer, vocabulary: string, pronunciation: string, viewing: integer, meaning: text, example: text, created_at: datetime, updated_at: datetime)
find_by
irb(main):058:0> Word.find_by(pronunciation: "さぎ").class
Word Load (0.9ms) SELECT `words`.* FROM `words` WHERE `words`.`pronunciation` = 'さぎ' LIMIT 1
=> Word(id: integer, vocabulary: string, pronunciation: string, viewing: integer, meaning: text, example: text, created_at: datetime, updated_at: datetime)
Wordのインスタンスを返す
where
irb(main):066:0> Word.where("id in (2, 4)").class
=> Word::ActiveRecord_Relation
検索結果がない場合
find
irb(main):069:0> Word.find(5)
Word Load (1.1ms) SELECT `words`.* FROM `words` WHERE `words`.`id` = 5 LIMIT 1
/usr/local/bundle/gems/activerecord-7.0.4.2/lib/active_record/core.rb:284:in `find': Couldn't find Word with 'id'=5 (ActiveRecord::RecordNotFound)
例外ActiveRecord::RecordNotFound
が発生
find_by
irb(main):070:0> Word.find_by(id: 5)
Word Load (0.7ms) SELECT `words`.* FROM `words` WHERE `words`.`id` = 5 LIMIT 1
=> nil
nil
を返す
where
irb(main):073:0> Word.where("id > 5")
Word Load (0.9ms) SELECT `words`.* FROM `words` WHERE (id > 5)
=> []
空きの配列に見えるが
irb(main):074:0> Word.where("id > 5").class
=> Word::ActiveRecord_Relation
型はActiveRecord_Relation
でした。