質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

3回答

971閲覧

0件のDBの検索における「ActiveRecord::RecordNotFound」について

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2017/08/22 01:28

編集2017/08/22 04:25

■前提条件
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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

mingos

総合スコア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

suzukis

総合スコア1449

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/08/22 04:19

>そこで、IDでリソースを検索するための特別なfind(id)というメソッドがあるわけです。 確かに。言われてみればfindはURLに含まれる固有のIDを特定するときに使います。 IDが引っかからなければ404が表示される・・・目から鱗です! 判りやすいご説明ありがとうございました! RESTについても調べてみたいと思います。
guest

0

ベストアンサー

findは、objectを返す
whereは、配列(厳密にはちょっと違うようですが)を返す

からです。試しに、値がある結果にinspectをつけて、結果を見てみると分かりやすいと思います。

投稿2017/08/22 01:34

Yuinyan

総合スコア312

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/08/22 01:35

ありがとうございます!試してみます!!
退会済みユーザー

退会済みユーザー

2017/08/22 01:55

試してみたところ、確かにfindはObjectでwhereは配列?で返されていました。 findの場合 #<Hoge id: 1, created_at: "2017-08-22 00:00:00", updated_at: "2017-08-22 00:00:00"> whereの場合 #<ActiveRecord::Relation [#<Hoge id: 1, created_at: "2017-08-22 00:00:00", updated_at: "2017-08-22 00:00:00">]>
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問