はじめまして。
現在、1つのモデルに対して、一度の投稿で複数のレコードを登録する機能を実装しています。
もし入力ミスがあった場合、再度入力フォームに戻り、Validationエラーを表示させたいのですが、Formオブジェクトモデルのインスタンスのerrorsに、エラーメッセージが格納されていないからか、表示されません。お知恵をお借りしたく、何卒よろしくお願いします。
Version
Ruby on Rails 6
発生している問題・エラーメッセージ
- 入力箇所にエラーがあった場合、「再度入力フォームに戻る」ことはできているが、validationエラーの文章が表示されない。
該当のソースコード
① コントローラー
Ruby
class FoodsController < ApplicationController def new @form = Form::FoodCollection.new(params[:box_id]) end def create @form = Form::FoodCollection.new(food_collection_params) if @form.save == true redirect_to root_path, notice: "商品を登録しました" else render :new end end private def food_collection_params params.require(:form_food_collection) .permit(:food_title, :number_title, :purchase_date, :expiry_date, :price, :give_id) .merge( box_id: params[:box_id] ) end end
②Formオブジェクトモデル
Ruby
# Base class Form::Base include ActiveModel::Model include ActiveModel::Callbacks include ActiveModel::Validations include ActiveModel::Validations::Callbacks end # Baseを継承したFoodCollectionモデル class Form::FoodCollection < Form::Base FORM_COUNT = 3 #ここで、作成したい登録フォームの数を指定 attr_accessor( :foods, :food_title, :number_title, :purchase_date, :expiry_date, :price, :give_id, :box_id ) with_options presence: true do validates :food_title validates :number_title validates :purchase_date validates :expiry_date validates :price validates :give_id end # 初期化メソッド def initialize(box_id, attributes = []) if attributes.present? self.foods = attributes.map do |value| Food.new( food_title: value["food_title"], number_title: value["number_title"], purchase_date: value["purchase_date"], expiry_date: value["expiry_date"], price: value["price"], give_id: value["give_id"], box_id: value["box_id"] ) end else self.foods = FORM_COUNT.times.map { Food.new } end end def persisted? false end def save is_success = true Food.transaction do self.foods.each do |result| is_success = false unless result.save end raise ActiveRecord::RecordInvalid unless is_success end rescue p 'error' ensure return is_success end
③View
Ruby
<div class="items-sell-main"> <h2>冷蔵庫に入っている食材を入力しよう!</h2> <div id="div_default"><h2>上の食材カテゴリを選んでね</h2> </div> <%= form_with model: @form, url: box_foods_path, method: :post, local: true do |fr| %> <%= render 'shared/error_messages', model: fr.object %> <div id="div_fish"> <%# <%= render partial: 'shared/fields_for', locals:{ form: form } %> <h2>選択されている食材カテゴリ : <i class="fa-solid fa-fish"></i>Fish </h2> <table class="item-table"> <thead> <tr class="item-tr"> <th>魚の食材名</th> <th>個数</th> <th>購入日</th> <th>消費期限</th> <th>購入価格</th> <th>不要チェック</th> </tr> </thead> <tbody> <%= fr.fields_for :foods do |f| %> <tr> <td><%= f.text_field :food_title %></td> <td><%= f.number_field :number_title, min: 1, max: 99 %></td> <td><%= f.date_field :purchase_date %></td> <td><%= f.date_field :expiry_date %></td> <td><%= f.text_field :price %></td> <td><%= f.check_box :give_id, {}, "true", "false" %></td> </tr> <% end %> </tbody> </table> </div>
▼renderのエラーメッセージ部分
Ruby
<% if model.errors.any? %> <div class="error-alert"> <ul> <% model.errors.full_messages.each do |message| %> <li class='error-message'><%= message %></li> <% end %> </ul> </div> <% end %>
自分で調べたことや試したこと
仮説① : saveメソッドで保存するとき、validationのエラー文が発生していない?
- ②Formオブジェクトのsaveメソッドでbinding.pryを行ったところ、error文はちゃんと発生していた。
仮説② : Formオブジェクトだと、エラー文が更新されていかない?
- 通常のモデルだと、エラー文は@モデルのインスタンス.errorsに格納されていく
- Formオブジェクトでは、エラー文がerrorsに格納されない??
- そうであれば、生成されたエラー文を手動で@インスタンス.errorsに格納しないといけない??
- ▼@インスタンス.errorsの中身を確認したところ、ActiveModel::Errors:0x000~といったオブジェクトの格納は確認できますが、ここの値を更新する方法がわかりませんでした。
ruby
[25] pry(#<#<Class:0x00007fb8f7ec4318>>)> @form.errors => #<ActiveModel::Errors:0x00007fb8e0da9a08 @base= #<Form::FoodCollection:0x00007fb91034b658 @box_id="38", @errors=#<ActiveModel::Errors:0x00007fb8e0da9a08 ...>, @foods= [#<Food:0x00007fb910371b28 id: nil, food_title: "にしん", number_title: nil, purchase_date: nil, expiry_date: nil, price: nil, give_id: 0, box_id: 38, created_at: nil, updated_at: nil>, #<Food:0x00007fb8e141c5c0 id: nil, food_title: "さけ", number_title: nil, purchase_date: nil, expiry_date: nil, price: nil, give_id: 0, box_id: 38, created_at: nil, updated_at: nil>, #<Food:0x00007fb8e1427970 id: nil, food_title: "さば", number_title: nil, purchase_date: nil, expiry_date: nil, price: nil, give_id: 0, box_id: 38, created_at: nil, updated_at: nil>]>, @details={}, @messages={}>
長文かつ分かりにくい箇所があるかと思いますが、何卒よろしくお願いします。
まだ回答がついていません
会員登録して回答してみよう