■前提条件
RubyonRailsでRails5.0系を使用しています。
■疑問事項
findとWhereを使って0件のDBの検索を行った場合の挙動について
Ruby
1@hoge = Hoge.find(1)
結果
⇒ActiveRecord::RecordNotFound
Ruby
1@hoges = Hoges.where(id:1)
結果
⇒View側には何も表示されない状態(DBが0件だから)
ここで疑問点ですが、findを使うとなぜデータが一件も無い場合は、
「ActiveRecord::RecordNotFound」になるのでしょうか?
なぜwhereは一件もなくても「ActiveRecord::RecordNotFound」
が発生しないのでしょうか?
初歩的な質問かと思いますがご回答をお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
なぜ?と思うほうが不思議です。
findとwhereというまったく異なる命令を使っているのだから、動きが異なるのは自然でしょう。
この場合は、findの場合はレコードが見つからない場合は例外が発生する。
whereは例外は発生しない。
という挙動を理解して、必要に応じて使い分ければいいんだなと解釈すべきところです。
どうしても気になるなら、直接railsの該当コードを読むのが正しいです。
ちなみにfindのコードはこうなっています。
単純にレコードがない場合は、例外を発生させているという事が分かるでしょう。
なぜとか疑問に思う余地はありません。
そういう仕様だからです。
ruby
1module ActiveRecord 2 module Core 3 4 def find(*ids) # :nodoc: 5 # We don't have cache keys for this stuff yet 6 return super unless ids.length == 1 7 # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5 8 return super if ids.first.kind_of?(Symbol) 9 return super if block_given? || 10 primary_key.nil? || 11 default_scopes.any? || 12 current_scope || 13 columns_hash.include?(inheritance_column) || 14 ids.first.kind_of?(Array) 15 16 id = ids.first 17 if ActiveRecord::Base === id 18 id = id.id 19 ActiveSupport::Deprecation.warn(<<-MSG.squish) 20 You are passing an instance of ActiveRecord::Base to `find`. 21 Please pass the id of the object by calling `.id` 22 MSG 23 end 24 key = primary_key 25 26 s = find_by_statement_cache[key] || find_by_statement_cache.synchronize { 27 find_by_statement_cache[key] ||= StatementCache.create(connection) { |params| 28 where(key => params.bind).limit(1) 29 } 30 } 31 record = s.execute([id], self, connection).first 32 unless record 33 raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}" 34 end 35 record 36 rescue RangeError 37 raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'" 38 end 39 40 end 41 42end
一方で、whereのコードはこうなっています。
この時点では例外を発生させる処理がないので例外は起きないのは道理です。
ruby
1module ActiveRecord 2 module QueryMethods 3 4 def where(opts = :chain, *rest) 5 if opts == :chain 6 WhereChain.new(spawn) 7 elsif opts.blank? 8 self 9 else 10 spawn.where!(opts, *rest) 11 end 12 end 13 14 end 15end
投稿2017/08/22 01:38
総合スコア4025
0
RESTアーキテクチャに沿ったアプリケーションを作るのがRailsの思想です。RESTについて詳しく説明はしませんが、URLに含まれる固有のIDでリソースを特定しそれに対して操作を行う形になりますので、IDで検索するというのは重要かつ頻出する処理になります。そこで、IDでリソースを検索するための特別なfind(id)
というメソッドがあるわけです。
さらに、コントローラ内でActiveRecord::RecordNotFound
が発生すると、コントローラはクライアントに404 not foundを返します。scaffoldで生成されるコードを見るとわかりますが、レコードが見つからなかった場合の処理はアプリケーションコードに現れません。IDで検索してひっからなかったら404になるのはRESTでは自明なので、いちいち書かなくても自動でそうなるようになっているわけです。
投稿2017/08/22 04:03
総合スコア1449
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
findは、objectを返す
whereは、配列(厳密にはちょっと違うようですが)を返す
からです。試しに、値がある結果にinspectをつけて、結果を見てみると分かりやすいと思います。
投稿2017/08/22 01:34
総合スコア312
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/08/22 01:35
退会済みユーザー
2017/08/22 01:55
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。