付録E よくあるエラーと対処
Hotwire でつまずきやすいエラーと、その対処をまとめます。多くは、第29章の観察の手順(Network → Turbo イベント → Stimulus → target → morph)で原因にたどり着けます。
フォームを送っても何も起きない
症状: フォームを送信したのに、画面が変わらず、エラーも出ない。
原因: 失敗時に 422 ではなく 200 でフォームを返している。Turbo Drive は、非 GET のフォーム送信へのリダイレクトなしの 200 HTML を描画せず、送信元の URL に留まります(第8章)。
対処: 失敗時は render ..., status: :unprocessable_entity(422)で返す。成功時はリダイレクト(update / destroy は status: :see_other)。
frame が空になる/案内メッセージが出る(Content missing)
症状: frame の中身が消える、または「Content missing」のような案内が出て、Console に例外が出る。
原因: リンク先のレスポンスに、同じ id の <turbo-frame> がない(第11章)。
対処: リンク元とリンク先の両方に、同じ id の frame があるか確認する。dom_id を使い、手書きの id がずれていないかを見る(第17章)。
Turbo Streams の命令が効かない
症状: stream を返しているのに、画面が更新されない。
原因: target が指す id の要素が、画面に存在しない。存在しない id への命令は、静かに何も起こしません(第29章)。
対処: Network タブで stream の中身を見て、target の id が DOM にあるか、Elements タブで確認する。
Stimulus のコントローラが動かない
症状: data-controller を付けたのに、振る舞いが動かない。
原因: コントローラ名とファイル名のずれ、ファイルの置き場所の誤り、target / action の名前の不一致(第19章・第20章)。
対処: application.debug = true にして、接続ログが出るか見る(第29章)。出なければ名前と置き場所、出れば target / action の名前を疑う。
戻る・進むで、古い内容や壊れた表示が出る
症状: 戻る操作で、古いフラッシュや、初期化済みのウィジェットが一瞬出る。
原因: 復元用のスナップショットに、消したい要素や JavaScript で書き換えた DOM が残っている(第9章・第22章)。
対処: 一度きりの要素には data-turbo-temporary を付ける。外部ライブラリは turbo:before-cache で後始末する。application visit のプレビューだけを止めるなら no-preview、戻る操作でのキャッシュ復元も止めるなら no-cache。
外部ライブラリが二重に初期化される
症状: 画面を行き来すると、ライブラリが重複して動く、残骸が残る。
原因: connect() で初期化したものを、disconnect() で破棄していない(第22章)。
対処: disconnect() で destroy() し、タイマーやリスナーも片付ける。
リアルタイム更新が届かない
症状: 他のユーザーの操作が、自分の画面に反映されない。
原因: 購読先(turbo_stream_from)と配信先(broadcasts_to / broadcast_*_to)の指す相手がずれている。または、update_all などの一括更新で callback が走っていない(第18章)。
対処: 購読先と配信先が同じ streamable を指しているか確認する。一括更新では broadcast が走らないことに注意する。
解決しないときは、最小の再現コードを作り、第29章の手順で 1 つずつ切り分けてください。
キャッシュと認証切れを切り分ける
no-preview は application visit のプレビューだけを止めます。戻る・進むで古いスナップショットを使わせたくないなら no-cache を選びます。
フレーム内操作がログインへ転送されて Content missing になる場合は、ログインビューに <% turbo_page_requires_reload %> を加えます。ログイン画面をフレームの外で表示させるための指定です。