0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Error】`Form responses must redirect to another location`のエラー

Last updated at Posted at 2024-09-23

はじめに

今回は「診断する」ボタンを押したときに発生したエラーについて。解決までの流れを記事にまとめてみました。

環境

  • Windows, WSL
  • Docker
  • Ruby 3.2.3
  • Rails 7.1.3

エラー状況

Image from Gyazo

1つめのエラー

application-69fa277eb9bd4e308e5353b0008b7268a08e7361b5d65e56705847ea8b96f7f4.js:4026 Error: Form responses must redirect to another location
    at _FormSubmission.requestSucceededWithResponse (application-69fa277eb9bd4e308e5353b0008b7268a08e7361b5d65e56705847ea8b96f7f4.js:1641:22)
    at FetchRequest.receive (application-69fa277eb9bd4e308e5353b0008b7268a08e7361b5d65e56705847ea8b96f7f4.js:1389:21)
    at FetchRequest.perform (application-69fa277eb9bd4e308e5353b0008b7268a08e7361b5d65e56705847ea8b96f7f4.js:1367:25)

2つめのエラー

new:1 Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

調べてみるとどちらも「Rails アプリケーションの JavaScript とフォームの送信に関連」しているそうです。

1つ目のエラー: Form responses must redirect to another location

内容:

このエラーは、フォームを送信した後に、Rails が適切にリダイレクトを行わなかった場合に発生するもので、通常、Rails のフォーム送信は、成功した後に別のページにリダイレクトされる必要があります。

エラー原因

  1. 「診断する」ボタンの押下後、リダイレクトがないことフォームが送信された後、ページは通常 POST リクエストを送信し、結果を表示するために別の場所にリダイレクトする必要があります。現在、フォームは POST /posts を実行していますが、結果を表示するためのリダイレクト処理が不足している可能性がある状態!

👇こちらの記事を参考にしつつも手探りで。

解決策:postsコントローラー

  1. リダイレクトを追加するcreate アクションを追加し、フォームが送信された後、診断結果を表示する index アクションにリダイレクトするように変更します

変更前

class PostsController < ApplicationController
  def new
    # フォームを表示するためのアクション
  end

  def index
    # パラメータを取得
    question1 = params[:question1]
    question2 = params[:question2]
    question3 = params[:question3]
    question4 = params[:question4]
    question5 = params[:question5]

    # 「はい」(1)の数を合計
    yes_count = [question1, question2, question3, question4, question5].map(&:to_i).sum

    # 結果に基づいて表示する内容を決定
    @result = yes_count

    # 診断結果用にすべてのPostレコードを取得
    @posts = Post.all
  end
end

変更後

class PostsController < ApplicationController
  def new
    # 新規フォームを表示
  end

  def create
    # フォーム送信後の処理
    redirect_to posts_path(
      question1: params[:question1],
      question2: params[:question2],
      question3: params[:question3],
      question4: params[:question4],
      question5: params[:question5]
    )
  end

  def index
    # パラメータを取得
    question1 = params[:question1]
    question2 = params[:question2]
    question3 = params[:question3]
    question4 = params[:question4]
    question5 = params[:question5]

    # 「はい」(1)の数を合計
    yes_count = [question1, question2, question3, question4, question5].map(&:to_i).sum

    # 結果に基づいて表示する内容を決定
    @result = yes_count

    # 診断結果用にすべてのPostレコードを取得
    @posts = Post.all
  end
end

解決策:ルーティング

変更前

  # トップページ
  root 'tops#index'

  # 診断フォームを表示するルート
  get 'posts/new', to: 'posts#new', as: :new_post

  # 診断結果を表示するためのルート
  post 'posts', to: 'posts#index', as: :posts

変更後

  # トップページ
  root 'tops#index'

  # 診断フォームを表示するルート
  get 'posts/new', to: 'posts#new', as: :new_post

  # 診断結果を表示するためのルート
  post 'posts', to: 'posts#create', as: :posts

  # 診断結果ページ
  get 'posts', to: 'posts#index', as: :result_posts
  • root 'tops#index': トップページは tops#index アクションを表示します。
  • get 'posts/new', to: 'posts#new', as: :new_post: 診断フォームのページです(/posts/new)。
  • post 'posts', to: 'posts#create', as: :posts: 診断フォームの送信先です(POST /posts)。
  • get 'posts', to: 'posts#index', as: :result_posts: 診断結果のページにアクセスするルート(GET /posts)です。 create アクションからこの index アクションにリダイレクトされます

def create が必要な理由を簡単に】

まず、def newdef index の役割について

  • new メソッド:新しい診断フォームを表示するページを担当します。このページでユーザーは診断に必要な情報を入力します。new は単にフォームを表示するだけで、データを保存したり処理をしたりはしません。
  • index メソッド:診断結果を一覧で表示するページを担当します。このメソッドではすでに保存されたデータ(診断結果など)を取得して、ユーザーに見せます。

次に、create メソッドがなぜ必要か?

  • create メソッド:診断フォーム(new メソッドで表示されるもの)にユーザーが入力したデータを受け取り、サーバーにそのデータを送信して保存する役割を持っています。ユーザーがフォームに入力し「送信」ボタンを押すと、POSTリクエストがサーバーに送られます。このリクエストはcreate メソッドによって処理され、データベースに新しい診断結果が保存されます。

簡単にまとめると:

  1. new はフォームを表示するだけ(データの保存はしない)。
  2. create はフォームのデータを保存する(データが保存されないと結果を表示できない)。
  3. index は保存されたデータを表示するため、createでデータが保存されていないと意味がない。

つまり、new でフォームを作り、createでそのフォームからデータを受け取って保存し、その後indexで保存された結果を表示する、という流れになります。

2つ目のエラー: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

このエラーは、JavaScript が非同期的に応答を期待しているのに、予期せぬ理由で通信が中断された場合に発生します。通常、Rails の Turbo や Ajax 機能が適切に動作していないことが原因のようで、解決策としては次の3つが挙げられます

解決策:

  • アプリケーションの JavaScript コードに問題がないか確認します。
  • もし Turbo を使っているなら、非同期リクエストに対する正しい応答を処理するようにしてください。
  • Turbo を無効にして、通常のフォーム送信を試みることもできます。例えば、フォームタグを次のように変更します。

拡張機能によるものという記事も見られましたがとりあえずはturboに関する部分を見てみました

👇Turbo を無効にして、通常のフォーム送信するようにしてみる

変更前

# app/views/posts/new.html.erb
<%= form_tag(posts_path, method: :post) do %>

変更後

<%= form_tag(posts_path, method: :post, data: { turbo: false }) do %>

さいごにまとめ

一応上記の通りに修正することでエラーが解消されたので一安心。
ただ2つ目のエラーに関してはまだ時間がたつといつの間にか発生している状態です。
拡張機能で何か原因があるのかも

今回の記事が何か参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?