Railsでアプリケーションの開発をするようになってもう数ヶ月経ちますが、findやらfind_byやら(whereやら)の明確な違いをよく分からないまま使ってしまっていたので、色々触ってまとめてみました。
findメソッド
findメソッドを使用すると、与えられたどのオプションにもマッチする 主キー に対応するオブジェクトを取り出すことができます。
引用:Active Record クエリインターフェイス - Railsガイド
やっぱり文章でみるとなんのことやらさっぱりですね。
user = User.find(1) = > #<User:0x00007fa52df33ca0 id: 1, name: "hoge">
ちなみにfindメソッドでは単一のレコードしか取得できないと思ってたけど、以下のように複数指定することもできるみたい。(あんまりこういう取り方はしないと思うけど)
user = User.find(1, 5) = > #<User:0x00007fa52df33ca0 id: 1, name: "hoge"> = > #<User:0x00007fa52e36e860 id: 5, name: "fuga">
ただしこの場合、指定した引数のうち一つでも存在しないレコードがあるとエラーになる。
user = User.find(1, 50) ActiveRecord::RecordNotFound: Couldn't find all Users with 'id': (1, 50) (found 1 results, but was looking for 2)
(idが50のユーザーは存在しない)
find_byメソッド
find_byメソッドは、与えられた条件にマッチするレコードのうち最初のレコードだけを返します。
引用:Active Record クエリインターフェイス - Railsガイド
user = User.find_by(name: "hoge") User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'hoge' LIMIT 1 = > #<User:0x00007fa52df33ca0 id: 1, name: "hoge">
これは以下のようにも書き換えられる。
user = User.where(name: "hoge") User Load (4.7ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'hoge' = > #<User:0x00007fa52df33ca0 id: 1, name: "hoge">
whereは言わずもがなマッチする全てのレコードを取り出してくれるので、クエリを見てみると最後の「LIMIT 1」がないところが唯一の違い。
あとおそらく全レコードをチェックした上で結果を返してくるので、検索にかかる時間もfind_byの方が圧倒的速さですね。
findとfind_byの違い
で、findとfind_byの違いって「条件をidで指定するかどうか」ぐらいかなと思っていたんだけど、実際にはもっと明確な(というか知っておくと便利?な)違いがあった。
それがnilを渡したときにエラーになるかならないかということ。
findの場合
user = User.find(nil) User Load (2.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = NULL LIMIT 1 ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
find_byの場合
user = User.find_by(id: nil) User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1 => nil
findの場合はエラーになっちゃうけど、find_byの場合はnilを返してくれる。
明確にそのオブジェクトが存在するかどうか分からない場合の処理なんかには、findを使わずにfind_byでエラー対策をした方が良さそうですね。
まとめ
findとfind_byの違い、find_byとwhereの違いをしっかり理解していなかったので、今後きちんと使い分けしていこうと思います。