🧦

バリデーションは効いているのにエラーメッセージが出ないときの対処法

2023/10/02に公開

この記事で分かること

  • エラーメッセージが出ない原因のパターン
    → (status: :unprocessable_entity)を追加
    → formで(local: true)を追加
    → createアクションの見直し

完成イメージ

  • Before
    before_demo

  • After
    after_demo

解決した添削コード
items_controller
class Public::ItemsController < ApplicationController
  def create
    @item = Item.new(item_params)
    @item.user_id = current_user.id
    if @item.save
      flash[:notice] = "投稿に成功しました"
     redirect_to item_path(@item)
    else
     @items = Item.order("created_at DESC").page(params[:page])
-    @item = Item.new
     @user = current_user
     @genres = Genre.all
     @products = Product.where(is_secret: true)
     flash[:alert] = "投稿に失敗しました"
     render 'index'
    end
  end

  def index
    @products = Product.where(is_secret: true)
    @items = Item.order("created_at DESC").page(params[:page])
    @user = current_user
    @item = Item.new
    @genres = Genre.all

    if params[:latest]
      @items = Item.latest.page(params[:page])
    elsif params[:most_commented]
      @items = Item.most_commented
      @items = Kaminari.paginate_array(@items).page(params[:page])
    elsif params[:most_favorited]
      @items = Item.most_favorited
      @items = Kaminari.paginate_array(@items).page(params[:page])
    else
      @items = Item.order("created_at DESC").page(params[:page])
    end
  end
end

解決策を3つ紹介

私が実践した解決策は以下の3点です。

  • renderに(status: :unprocessable_entity)を追加
  • formで(local: true)の記述を確認
  • createアクションの見直し

私は「createアクションの見直し」で解決しました。

1.renderに(status: :unprocessable_entity)を追加

items_controller
    else
     @items = Item.order("created_at DESC").page(params[:page])
     @user = current_user
     @genres = Genre.all
     @products = Product.where(is_secret: true)
     flash[:alert] = "投稿に失敗しました"
+    render 'index', status: :unprocessable_entity
    end
  end

Railsのバージョンによっては、エラーメッセージを出力するには上記の記述を追加する必要があるらしいです。私は記述してみましたが変化はありませんでした。

2.formで(local: true)の記述を確認

items/_form
<%= form_with model: item, local: true do |f| %>

formに(local: true)を記述していない場合も、エラー文が出ない原因になるそうです。
理由として、記述していないデフォルト状態では、(remote: true)になっているからです。
今回は、Ajax処理は必要がないので、local: tureと記述されているか確認します。

3.createアクションの見直し

items_controller
class Public::ItemsController < ApplicationController
  def create
    @item = Item.new(item_params)
    @item.user_id = current_user.id
    if @item.save
      flash[:notice] = "投稿に成功しました"
     redirect_to item_path(@item)
    else
     @items = Item.order("created_at DESC").page(params[:page])
-    @item = Item.new
     @user = current_user
     @genres = Genre.all
     @products = Product.where(is_secret: true)
     flash[:alert] = "投稿に失敗しました"
     render 'index'
    end
  end

(render)の記述を確認したときに、@Item.newとして再定義していることに気づきました。
新しく定義するとバリデーションしていない(まだ投稿していない)Itemを参照することになり、エラー文が出てこないみたいでした。

感想

エラー文の設定の見積もりを30分ぐらいで考えていましたが、ここまでで1時間ぐらいかかってしまいました。日本語化も少し苦戦したので、また記事にしようと思います。

この記事をかいた人

https://twitter.com/tya_dwc
23/6/1にDWCに入学し、主にRailsの学習に取り組みました。卒業が近づきこれから何で学習をするか悩んだときに、技術ブログをしようと考えました。初心者ですがよろしくお願いします。

Discussion