AcitveRecord::RecordNotFound in … Couldn’t find (A) with (B) の原因と対処法【Ruby on Rails 初心者向け】

Ruby on Rails

AcitveRecord::RecordNotFound in … Couldn’t find xxx with xxx というエラーメッセージが出て修正の目処がたちません。

どうすれば正しく動くでしょうか。

そんな疑問にお答えします。

このエラーは Ruby on Rails でよく見るエラーですので困っている人も多いのではないでしょうか。

このエラーに対処するためには Ruby on Rails のモデルの使い方に習熟する必要があります。
逆に言えば対処できるようになっているころには、モデルの使い方がうまくなっています。

私が見てきた Rails 初心者の人たちも最初は何が起きているか戸惑っていたものの、何度か対処に挑戦しているうちにモデルの使い方がうまくなり、自然と対応できるようになっていきました。
この記事を読んで実際のエラーに対処できるようになればRailsのコーディング力が一段と向上しますよ!

原因: find メソッド実行時に指定した id のレコードが見つからない

AcitveRecord::RecordNotFound はモデルの find メソッドを実行したときに発生するエラーです。

ほとんどの場合、指定した id を持つレコードがテーブルに存在しないのが原因です。

一般的な対処方法

指定した id に相当するレコードがテーブルに無いことが直接の原因です。
しかし、ほとんど場合指定した id 自体が間違っているということが問題です。

なので指定する id を正しくすれば治ることがほとんどです。

例えば

def show
  @book = Book.find(params[:id])
end

このコードは 「id というパラメータで送られてきた値」で books テーブルから探すコードです。

存在しない id を指定した場合以下のようなエラー画面になります。

修正するには

  1. find メソッドに渡している params[:id] がどこから来ているのかを確認
  2. そこを正しい値が渡ってくるように修正する

という手順が必要です。

よくある間違いと対処法

一般論を解説したところで、ここからはよくある間違いとその対処法を解説していきます。

基本的には find メソッドに渡ってくる値がどこから来ているのかを確認してそれを正しくするという基本は同じです。

それでは見ていきましょう!

params[:xxx] の xxx (パラメータ名)を間違えている

よくある間違いはパラメータ名を間違えていることです。

例えば、

@book = Book.find(params[:id])

のようなコードを書いていたけど、本当は

@book = Book.find(params[:book_id])

だった!のような場合です。

これを修正するにはエラー画面に Request セクションの Parameters: のところを確認してみましょう。

どれが正しいかはそのアプリの仕様によるところですが、かなりのヒントになると思います。

xxx_path メソッドの引数のルールを勘違いしている

リンクやリダイレクトの遷移先を間違えている場合にもAcitveRecord::RecordNotFoundが起きやすいです。

例えば、

link_to "リンク", book_path(@book)

のようなコードがある場合、

<a href="/books/1">リンク</a>

のようなリンクができます。(ただし @book に id = 1 のインスタンスが入っている場合)

このときルーティング(rails routes コマンドの結果)が

   Prefix Verb   URI Pattern               Controller#Action
     book GET    /books/:id(.:format)      books#show

となっていれば BooksController の show アクションを実行するわけですが、その show が

def show
  @book = Book.find(params[:id])
end

となっている場合です。

リンクが /books/1 となっていて URI パターンが /books/:id なので params[:id] には 1 が入ります。

rails routes コマンドの読み方については以下を参照してください。
rails routes コマンドの読み方を徹底解説

このとき books テーブルに id = 1 のレコードがなければ AcitveRecord::RecordNotFound が発生します。

対処方法としては

link_to "リンク", book_path(@book)

の @book に入っているインスタンスがリンク先のページの

  • モデル
  • id

であるかを確認することです。

これはリダイレクトのときも同じ原理です。

redirect_to book_url(@book)

の場合に @book に入っているインスタンスが正しいかどうかを確認してみましょう。

find と find_by を間違えている

Rails 初心者にありがちな勘違いは find メソッドと find_by メソッドの取り違いです。

違いを確認しておきましょう。

  • find(数字) で id = 数字のレコードを取得する
  • find_by(ハッシュ)でハッシュを条件で検索し、その1件目を取得する

find_by(id: 数字) とすると id = 数字のレコードを取得することになり、find(数字) と同じに見えます。

しかし、find メソッドと find_by メソッドは見つからなかったときの挙動に差があります。

見つからなかったときの動作は以下のように定義されています。

  • find メソッド → エラーになる
  • find_by メソッド → nil を返す

このエラーとなる場合に発生するのがActiveRecord::RecordNotFoundです。

この挙動の差によって find メソッドと find_by メソッドを使い分ける必要があります。

つまり

  • 指定した id が存在しないことが想定されない場合 → find メソッドを使う
  • 指定した id が存在しないことが想定される場合 → find_by メソッドを使う

このように似ているけど動作が異なるメソッドについてもしっかりと理解しておくと不要なエラーを防ぐことができます。

削除したあとそのモデルの詳細ページにアクセスしている

仕様面の誤りや勘違いでActiveRecord::RecordNotFoundが発生することがあります。

特に多いのが以下のシチュエーションです。

詳細画面に削除ボタンが有り、削除後、その詳細画面にリダイレクトしている

ちょうど今削除したばかりの詳細画面にリダイレクトしているということです。

削除しているので当然その id を持つレコードはなくなっており、 find でエラーになるというパターンです。

このような場合は詳細画面にリダイレクトしている事自体が誤りです。

詳細画面ではなく別のエラーにならない画面にリダイレクトするようにしましょう。

まとめ

AcitveRecord::RecordNotFound in … Couldn’t find (A) with (B) の原因と対処法について解説しました。

find メソッドの使い方と、その引数へ渡しているインスタンスがしっかりと把握できれば修正できますのでがんばりましょう!

その他の Rails エラー関連記事はこちら

タイトルとURLをコピーしました