LoginSignup
hiddy0329
@hiddy0329 (hiddy)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

[Ruby on Rails]フォームからの商品一括登録機能実装におけるエラーハンドリングができません

解決したいこと

Ruby on Railsで商品登録アプリを実装しています。
商品を一括で登録する機能を実装中のことです。
ビューにおいて、エラーメッセージを表示するためのファイルを作成したが、
他のファイルから「render」を用いて呼び出すことができない状況を解決したい。

発生している問題・エラー

商品登録を一括でできるようにするために、「コレクションモデル」を利用して
実装をしようと考えています。
しかし、エラーハンドリングをするために、新規登録画面のビューファイル(app/views/new.html.erb)に「render」でエラーメッセージの部分テンプレートを呼び込む記述をしても、実際に読み込んでくれません。

エラーメッセージ表示できないエラー.png

該当するソースコード

app/models/form/product_collection.rb

class Form::ProductCollection < Form::Base
  FORM_COUNT = 10 #ここで、作成したい登録フォームの数を指定
  attr_accessor :products 

  def initialize(attributes = {})
    super attributes
    self.products = FORM_COUNT.times.map { Product.new() } unless self.products.present?
  end

  def products_attributes=(attributes)
    self.products = attributes.map { |_, v| Product.new(v) }
  end

  def save
    Product.transaction do
      self.products.map do |product|
        if product.availability # ここでチェックボックスにチェックを入れている商品のみが保存される
          product.save
        end
      end
    end
      return true
    rescue => e
      return false
  end
end

app/models/form/base.rb

class Form::Base
  include ActiveModel::Model
  include ActiveModel::Callbacks
  include ActiveModel::Validations
  include ActiveModel::Validations::Callbacks

end

app/models/product.rb

class Product < ApplicationRecord
  with_options presence: true do
    validates :item_number, length: { maximum: 11 }
    validates :name, length: { maximum: 50 }
    validates :color
    validates :price, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
    validates :availability, inclusion: { in: [true, false] }
  end

  validates :note, length: { maximum: 50 }
end

app/controllers/products_controller.rb

class ProductsController < ApplicationController

  def new
    @form = Form::ProductCollection.new
  end

  def create
    @form = Form::ProductCollection.new(product_collection_params)
    if @form.save
      redirect_to new_product_path
    else
      render :new
    end

  end

  private

    def product_collection_params
        params.require(:form_product_collection)
        .permit(products_attributes: [:item_number, :name, :color, :price, :note, :availability])
    end

end

app/views/new.html.erb

<%= form_for(@form, url: products_path, method: :post) do |fb| %>
<div class="container">

<%= render partial:'error_messsages', model: fb.object %>

<table class="table">
<thead>
  <tr>
    <th width="60px">登録</th>
    <th>品番</th>
    <th>商品名</th>
    <th>色</th>
    <th>販売価格</th>
    <th>備考</th>
  </tr>
</thead>
<tbody class="bulk-registration-form">
<%= fb.fields_for :products do |f| %>
  <tr class="item">
  <td class="text-center">
  <%= f.check_box :availability, class: 'top10 registration-checkbox' %>
  </td>
  <td>
  <%= f.text_field :item_number, class: 'form-control' %>
  </td>
  <td>
  <%= f.text_field :name, class: 'form-control' %>
  </td>
  <td>
  <%= f.text_field :color, class: 'form-control' %>
  </td>
  <td>
  <%= f.text_field :price, class: 'form-control' %>
  </td>
  <td>
  <%= f.text_field :note, class: 'form-control' %>
  </td>
</tr>
<% end %>
</tbody>
</table>
<div class="text-center">
<%= fb.submit '一括登録', class: 'btn btn-primary' %>
<%= link_to "戻る", root_path, class: 'btn btn-success' %>
</div>
</div>
<% end %>

app/views/products/_error_messages.html.erb

<% 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 %>

自分で試したこと

 部分テンプレートを呼び出せないことに関して、よくあるのが、部分テンプレートのファイル名が間違っていることや、「render」で呼び出し先のディレクトリを記述する際の記述の仕方が間違っていることなどが挙げられるので、
それらの点をチェックしましたが、問題はありませんでした。
 では、その他のファイルに問題があるのかどうか点検しましたが、自分自身では見つけることができませんでした。
 このエラーで1日経過してしまっているので、どなたか教えていただきたいです。

0

2Answer

エラー内容から分かるようにテンプレートファイルが見つかりませんとのエラー内容です。
単純に指定するファイル名称間違っていません?

app/views/new.html.erbではerror_messsagesとmessageのsが一つ多いですね。

後、パーシャルへの変数の渡し方も気になりました。

もし変数がうまく渡せていない場合は下記のサイトでlocalsを調べて見てください。

0

Comments

  1. @hiddy0329

    Questioner
    アドバイスありがとうございます!
    単純なエラーでしたね。
    表記を直したところ、無事にエラー画面は解消され新規登録ページに遷移できました。

    しかし、今度はバリデーションに引っかかるような入力をして登録ボタンを押してもエラーメッセージが表示されません。

    ということはそもそもバリデーションが効いていないのか?
    と思ったのですが、
    app/models/form/product_collection.rbにて以下のようなsaveメソッドを定義しているので、
    チェックボックスにチェックがついていないデータは保存しないということはできています。

    この点のみを登録時にチェックするので、元々のバリデーションによるエラーメッセージは出ない
    ということなのでしょうか?

    ご存じでしたら教えていただきたいです。

まず、問題の切り分け。どこで問題が発生しているかを確認するのが良いと思います。
product.saveの後でbinding.irbをしてバリデーションがちゃんと発生しているかの確認を行う。
_error_messages.html.erbにデータがちゃんと渡っているか確認を行う。

など、画面が表示されるまでの流れを考えてデバック作業を行なって見てください。

バリデーションはちゃんと走っているとの前提で話しますね。

app/views/products/_error_messages.html.erbに記載されているmodelはForm::ProductCollectionのインスタンスであり、Productのインスタンスではありません。しかしerror_messageはProductのインスタンスに格納されています。なので、productsプロパティをeachで回して上げる必要があるかなぁと思います。


form_forは推奨されていないので、form_withを使用したほうが良いですよ
https://railsdoc.com/page/form_for

0

Your answer might help someone💌