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?

【Rails6→Rails8】errors.full_messagesが取得できないエラーのデバッグ

Posted at

はじめに

Rails6を使っている教材を、Rails8で取り組んでいます。
バリデーションエラーが表示されずハマったので、原因と解決策を残しておきます。

やりたいこと

  • Validationエラーの内容を表示したい

やったこと

  • Modelにvalidatesの記述
      validates :title, presence: true
      validates :content, presence: true
    
  • viewに@article.errors.full_messagesをeachメソッドで出力できるように記載
    <ul>
     <% @article.errors.full_messages.each do |message| %>
       <li><%= message %></li>
     <% end %>
    </ul>
    

エラー内容

  • 空のまま送信してもエラーメッセージが表示されない
  • ループ処理内に記載したliタグ自体が生成されていない

調査

  • コンソール上で確認したところ正常にValidationが効いている

    myapp(dev)> article = Article.new
    => #<Article:0x00007f1d3978bf88 id: nil, title: nil, content: nil, created_at: nil, updated_at: nil>
    myapp(dev)> article.valid?
    => false
    myapp(dev)> puts article.errors.full_messages
    Title can't be blank
    Content can't be blank
    => nil
    
  • オブジェクトにエラーが入っているかを確認:正常に動作していそう

      def create
        @article = Article.new(article_params)
        if @article.save
          redirect_to article_path(@article)
        else
          Rails.logger.debug "エラー内容: #{@article.errors.full_messages.inspect}"
          render :new
        end
      end
    
    • ログ
    エラー内容: ["Title can't be blank", "Content can't be blank"]
    

原因

Rails 7 では Turbo がデフォルトで有効になった

  • form_with を使うと、デフォルトで remote: true(非同期リクエスト)として扱われる
  • その結果、フォーム送信後のレスポンスが Turbo Stream として処理される

非同期処理の場合、render :new の結果が Turbo によって正しく適用されない

  • Rails 6 では render :new すると、HTMLがそのまま更新される
  • Rails 7 のデフォルト(Turbo 有効)では、サーバーが 200 OK を返すと、画面は更新されるが @article.errors が適切に反映されないことがある

422 ステータス(unprocessable_entity)を返さないと、バリデーションエラー時のフォーム描画が正しく動かない

  • render :new のデフォルトのステータスは 200 OK であるため、エラー時にも通常のページ遷移と同じ挙動をしてしまう
  • Turbo200 OK を受け取ると、「成功した」と判断してしまう
  • unprocessable_entity(422)を返せば、「フォームの再描画が必要なエラー状態」と正しく認識される

解決策

  • Turboをfalseにする

    = f.button :submit, data: { turbo: false }
    
  • 422ステータスを返すようにする

    render :new, status: :unprocessable_entity
    

どちらを選ぶか

個人的にはせっかくなのでTurboを使える422のほうが良いかと思い、こちらを選びました。
そもそもTurboはUX向上の為にデフォルトになったはずなので、あえて意図的に停止させなくてもよいかなと…
あと、フォームごとにTurboだったりTurboじゃなかったりすると、分かりづらいコードになってしまうと考えました。

終わりに

Railsのアップデートについてもっと学習が必要だと感じました。
参考にあげたZenn本にも時間があるときに取り組んでみようと思います。

参考

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?