Rails入門者のエラー対処


どんもー、@snskOgataです。

今回は前回書けなかった、Rails入門者のエラー対処について書いていこうと思います。
初めに断っておきますが、環境設定等でのエラーは、吐きそうになるので今回は触れません!(笑)
 
 
さて、入門時の開発でのエラー対処についてまず言えるのが
エラー文と仲良くなろう
ということですね
入門時の開発エラーは、エラー文を読めば解決できることが本当に多いように思います。

加えて、英語が苦手な方は
エラーでよく出てくる単語の意味を押さえる
ことが技術力を身に付ける第一歩だと思います。

 
今回の記事の大枠については右側のヘッダを見ていただけたらと思います。

では、さっそく試しに実際のエラーを見てみましょう

1. エラー画面について

エラーによって少し画面構成が違うかもしれませんが、上記の3つの部分をまず確かめるのが大事だと思います。
これらの部分は以下を示しています。

①エラーの大まかな説明、エラーが発生したクラス#メソッド名なども表記してくれる
②エラーの詳細、どこでエラーが起こったのかやその問題点、また訂正について提示してくれる
③エラーが生じたファイルの行を表示、エラー行は赤く提示してくれる

特に②の部分にはスペルミスのようなものであれば
Did you mean? XXXX 「お前が意図したのってXXXXじゃね?」
のような形で提示してくれるので、③の該当部分を修正するだけでエラーを修正できたりします。

この問題は上記のように解決まで書いてくれていますが、大事なのはその上の行で
undefined local variable or method 'post'
「'post'ってやつが、ローカル変数かメソッドか判らんけど未定義だよ」という部分
こういうように大体のエラー文では、②の部分で詳細な問題点を挙げてくれるので、その周辺を洗うだけで大体の問題は解決できます。
洗い出しについては後方で再び書こうと思います。
 

2. 自分がやろうとしたことと、エラー文に書かれていることのギャップを考える

例えば自分がログアウトしようとしている時に次のようなエラーが出たとしましょう

自分はログアウトしようとしているのに、②部分を見るとなぜか「id=sign_outでUserが見つかりません」というように、アプリ側は「検索・表示」を行おうとしていることがわかります。

ここから推察できる問題は
A.ルーティングでusers/sign_outの優先順位がusers/:idより低くなっている → routes.rbを確認
B.ログアウトボタンを押した時のHTTPメソッドが間違えている → application.html.erbを確認
このふたつが考えられます。

実際に確かめてみると、A.に関してはdevise_for :usersがresources :usersより上部に書いてあるため問題はありませんでした。
B.に関して見てみると、本来ログアウトはリンクに対してmethod: "delete"を宣言しなければいけないのに、それがなされていませんでした。
これを書き加えることによって、無事エラーを回避することができました。

この場合のように
「自分がやろうとしたこと」

「実際に起こったこと」
を比較してやることで問題の発見をしやすくなると思います。

3. エラーが起こったのがRMVCのどこなのかを考える

上記のように「自分がやろうとしたこと」を考えることで、どのアクションでエラーが起こったか、というのを見つけることができます。
1.であればPostsのEditページの表示、2.であればsign_out(DELETE users/sign_out)ですね。

ではアクションを把握した上で、そのアクション内のどこを探ればいいのか。
一番確実なのは「RMVC全ての部分について確認する」ことですが、これはコストが掛かります。
一発で何処を修正すればいいかわかれば良いのですが、最初からそうはいかないので、まずは全体としてどういう問題点があるのかを知った上で、ある程度”あたり”をつけて確認していくようにしましょう。
これを繰り返していると”あたり”の範囲が狭くなっていき効率が上がっていくと思います。

下図の流れに沿って確認点を挙げていきます。

3.1. URLアクセスに関して(①)

この部分はページ遷移前に、(A)正しいURLが作成されてない、あるいは(B)正しいHTTPメソッドが実行されていない、という問題が起こりえます。

(A)正しいURLが作成されていない

(A)であれば、(A')form_withやform_forで正しくモデルを渡せていない、あるいは(A'')正しいURIを設定できていないという可能性があります。
form_forとform_withでモデルを渡した場合のパスの作成については後日別の記事を作成したいと思っています。

(A')に関しては、そのページを作成しているアクション内で@を使ったインスタンス変数をしっかり宣言できているか、ページ内で@を使ったインスタンス変数をしっかり用いれているか?という確認点があります。
(A'')に関しては次の3.2.にも繋がってきますが、ルーティングをしっかり確認しましょう。Terminalで'rails routes'と打つと現在のアプリ内のURI一覧を確認することができます。

(B)正しいHTTPメソッドが実行されていない

これに関しては、殆どがDELETEメソッドによるもので、DELETE(Rails内ではdestroy)に関してはHTML内で明確に提示してあげないといけない、という理由から発生しているものです。
該当リンク部分に method :'delete'と含めることによって、それを示すことができます。

3.2. ルーティングに関して(②)

ルーティングに関して起こりうる問題としては、(C)resourcesに渡すコントローラーやメソッドが正しくない、(D)階層構造が上手く処理できていない、(E)書く順番による優先順位が間違っている、などが起こりえます。

(C)resourcesに渡すコントローラやメソッドが正しくない

よくあるミスとしては
・resourcesのスペルミス(自分はこれが多いです(笑))
・resourcesに渡すシンボル部分は複数形になること(例)○:posts, ×:post
・only:のあとに必要なアクションのシンボルを渡していない
などがあります。

(D)階層構造が上手く処理できていない

config/routes.rb
resources :users do
  resources :tweets only: [:index, :new, :create]
end

このような階層構造を取った場合のURIは例えば「/users/1/tweet/new」のようになります。
様々な階層構造について、どのように記述し、それに対してどういうようにアクセス出来るかを頭に入れておきましょう。
Terminalで'rails routes'とコマンドを打つことでURIについては確認できます。

(E)URIの優先順位が誤っている

URIは、config.routes.rbに書かれている順番に沿って優先順位が決まります。
2.の例では大丈夫だったのですが、例えば

config/routes.rb
resources :users
devise_for :users

と書いてしまった場合、新規登録画面に行きたくて、users/sign_upにアクセスしたのに、アプリ側はusers/id=sign_upにアクセスしてしまいエラーが発生してしまいます。
ルーティングの書く順番には気をつけましょう。

3.3. コントローラ・モデルの関して(③④)

モデルに関しては、 (F)モデルがちゃんと用意されているか?、という問題と(G)paramsの中身の間違い、の2つが挙げられます

(F)モデルの用意時のミス

ここで宣言されたもののうち'@'をつけたものはインスタンス変数といって、ビューで使用が可能になります(後々ではテストコードでも)。
変数がちゃんと宣言されているか、変数の中身がちゃんと入っているか、おかしな処理はしていないか?などを確かめましょう。
また、モデル同士の結びつきであるアソシエーション(belongs_toやhas_many)、バリデーションが間違えていないかをapp/modelsの該当モデルを確認しましょう。

(G)paramsの中身の間違い

createとupdateに関して、そこに渡ってくる前のnewとeditのビューでform_with、form_forでモデルを渡してアクションを呼び出した場合(例えばform_for @￰tweet do |f|)、
paramsの中身が階層構造になっている点に注意です
これによりストロングパラメータの設定部分で単にparams.permit(:text)などでは取得できず、params .permit(:tweet).permit(:text)などと設定する必要があります。

binding.pryなどのデバッガを使って
・モデルを渡してformを作った場合
・モデルを渡さずformを作った場合
でそれぞれ「paramsの中身がどういった構造になっているか」を一度確認してみるといいでしょう。

3.4. ビューに関して(⑤⑥⑦)

ビューに関しては、アクションを呼び出した後に起こったものなので、(H)コントローラから渡されたの変数が上手く使えていない、という場合があります。

(H)変数の扱いが間違っている

具体的にいうと、配列でないものを.eachメソッドにかけようとしていたり、所持していないプロパティにアクセスしたりなどが考えられます。
渡ってきた変数がどういった値を持っているのかを判断して、どういう記述なら良いのかを考えてみましょう。
もし、これが使いたいけど渡ってきた変数がその値を持っていない…という場合はコントローラに戻って、そこでモデルに対して適切に処理しましょう。

 
 
おさらいをしておくと
(A)正しいURLが作成されていない
(B)正しいHTTPメソッドが実行されていない
(C)resourcesに渡すコントローラやメソッドが正しくない
(D)ルーティングの階層構造が間違っている
(E)URIの優先順位が誤っている
(F)モデルの用意時のミス
(G)paramsの中身の間違い
(H)ビュー内での変数の操作ミス

もちろんこれだけではないのですが、大まかにこれらがアクションに伴ったエラー群という感じです。
これに加えてデータベース作成の際のマイグレーションファイルでのミスであったり、コードの単純な構造ミスのシンタックスエラーなどもあります。
こういうように全体としてどういうエラーがあるのかを把握しておくと、エラーと対面したときに落ち着いて対処していけると思います。
なかなか解消できない場合は、アクションの流れに沿ってひとつずつ問題がないかを確認していくのも手です。

エラーは自分ひとりで解決するのはなかなか大変なので、インターネットや周りの人たちにも頼りながら、上手くエラーと付き合えるようになっていきましょう!

おまけ(TECH::EXPERT受講生向け)

TECH::EXPERTの基礎試験ではRailsの問題は殆どがエラー対処を行うことになります。
問題の解答時には変更前と変更後のコードを記載しなければならないのですが、その際に役立つのがvsCode内の「ソース管理」です。
変更後、ファイル保存「Command + S」を押した後に画面左のタブの枝分かれしたものを選び、変更したファイルを選択すると、変更前と変更後の部分がそれぞれ赤と黄色?でハイライトしてくれます!

これをコピっとしてぺっとすれば解答が楽です!
ちなみに「Command + Shift + @」でvsCode内にターミナルが出せます!
あとはファイル一覧のファイルを二本指でタップ、あるいはcontrolを押しながらタップで出る「相対パスをコピー」を選べば、ファイルパスを取得できます。(「app/controllers/messages_controller.rb」こんな感じの)
これはコーディング中でも結構使えたりする小技なので覚えておくといいかもしれません!

基礎本試験の期日もジリジリと近づいていますが、模試でしっかり知識を定着させて望めば大丈夫だと思うので、頑張りましょう!!!