現在、一度の投稿で複数レコードを登録する機能を実装しています。
具体的に以下機能を実現したいと考えています。
❶ 食材をカテゴリ毎(魚/肉/飲料など)に入力欄を設ける。カテゴリは、タブで変更する。
❷ 例) 魚カテゴリを選択し、入力されたレコードには、魚カテゴリのidを付与したい。
❸ カテゴリのidは、jQueryを用いて、タブがクリックされると、自動的に取得できるよう実装している。
❹ カテゴリのidは、"hidden_field"で隠し、idだけサーバーサイドに送ろうとしている。
困りごと
上記❸❹の「カテゴリidをタブ切り替えごとに取得」して、フォームの送信と共に「サーバーサイドまで送る」ことは成功していますが、idが初めのレコードにしか反映されません。
繰り返しとなりますが、やりたいことは、食材のカテゴリに応じてidを付与したい(魚のタブから入力したのであれば、魚のカテゴリidが保存したい)のです。なぜ、初めのレコードにしか付与されないのでしょうか。お知恵をお貸しいただきたくお願いいたします。
Version
Ruby on Rails 6
jQuery 3.6.0
該当のソースコード
HTML
html
1 <div class="content-area"> 2 <%= form_with model: @form, url: box_foods_path, method: :post, local: true do |form| %> 3 <%= render 'shared/foods_error_messages', model: @form %> 4 <div class="content show"> 5 <%= render partial: 'shared/fields_for', locals:{ form: form } %> 6 </div> 7 8 <div class="content"> 9 <%= render partial: 'shared/fields_for', locals:{ form: form } %> 10 </div> 11 12 <div class="content"> 13 <%= render partial: 'shared/fields_for', locals:{ form: form } %> 14 </div> 15 16 <div class="content"> 17 <%= render partial: 'shared/fields_for', locals:{ form: form } %> 18 </div> 19 20 <div class="content"> 21 <%= render partial: 'shared/fields_for', locals:{ form: form } %> 22 </div> 23 24 <div class="sell-btn-contents"> 25 <%= form.submit "登録する" ,class:"sell-btn", id:"food-btn" %> 26 <%=link_to 'もどる', root_path, class:"back-btn" %> 27 </div> 28 <% end %> 29 </div>
render(フォーム表示部分)
Ruby
1<h2>選択されている食材カテゴリ : <i class="fa-solid fa-fish"></i>Fish </h2> 2<table class="item-table"> 3 <thead> 4 <tr class="item-tr"> 5 <th>登録</th> 6 <th>食材名</th> 7 <th>個数</th> 8 <th>購入日</th> 9 <th>消費期限</th> 10 <th>購入価格</th> 11 </tr> 12 </thead> 13 <%# TODO : フォーム追加できるようにする。https://web-tsuku.life/add-form-appendchild/ %> 14 <tbody> 15 <%= form.fields_for :foods do |f| %> 16 <tr class="item-tr"> 17 <td><%= f.check_box :availability, {}, "true", "false" %></td> 18 <td><%= f.text_field :food_title %></td> 19 <td><%= f.number_field :number_title, min: 1, max: 99 %></td> 20 <td><%= f.date_field :purchase_date %></td> 21 <td><%= f.date_field :expiry_date %></td> 22 <td><%= f.text_field :price %></td> 23 <td><%= f.hidden_field :category_id, id:"send-data" %></td> 24 </tr> 25 <% end %> 26 </tbody> 27</table>
jQuery
- 押下されたタブに応じて、hidden_fieldのvalueを書き換えています。
Javascript
1$(function() { 2 let tabs = $(".tab"); // tabのクラスを全て取得し、変数tabsに配列で定義 3 let tab_id = 1 4 $(".tab").on("click", function() { // tabをクリックしたらイベント発火 5 $(".active").removeClass("active"); // activeクラスを消す 6 $(this).addClass("active"); // クリックした箇所にactiveクラスを追加 7 const index = tabs.index(this); // クリックした箇所がタブの何番目か判定し、定数indexとして定義 8 $(".content").removeClass("show").eq(index).addClass("show"); // showクラスを消して、contentクラスのindex番目にshowクラスを追加 9 }) 10 11 $("#tab-fish.tab").on("click", function(){ 12 // どのタブが選択されたか判断 13 tab_id = $("#tab-fish.tab").data("value"); 14 $("#send-data").val(tab_id) 15 }); 16 17 $("#tab-veg.tab").on("click", function(){ 18 // タブのIDを取得 19 tab_id = $("#tab-veg.tab").data("value"); 20 $("#send-data").val(tab_id) 21 debugger; 22 }); 23})
Foods Controller
- こちらでnew/createアクションを定義しています。
- Formオブジェクトを組んで、複数レコードが登録できるよう実装しています。
Ruby
1class FoodsController < ApplicationController 2 def new 3 # @form = Form::FoodCollection.new(params[:box_id]) 4 @form = Form::FoodCollection.new 5 end 6 7 def create 8 @form = Form::FoodCollection.new(food_collection_params) 9 binding.pry 10 if @form.save == true 11 redirect_to root_path, notice: "商品を登録しました" 12 else 13 render :new 14 end 15 end 16 17 def edit 18 end 19 20 def update 21 end 22 23 def show 24 end 25 26 private 27 28 def food_collection_params 29 params.require(:form_food_collection) 30 .permit(foods_attributes: [:availability, :food_title, :number_title, :purchase_date, :expiry_date, :price, :give_id, :category_id]) 31 .merge( 32 box_id: params[:box_id] 33 ) 34 end 35end
Formオブジェクト
Ruby
1class Form::FoodCollection < Form::Base 2 FORM_COUNT = 3 3 #ここで、作成したい登録フォームの数を指定 4 attr_accessor( 5 :foods, 6 :availability, :food_title, :number_title, :purchase_date, :expiry_date, :price, :give_id, :category_id, 7 :box_id 8 ) 9 # foodsに作成したモデルが格納される 10 11 with_options presence: true do 12 validates :food_title 13 validates :number_title 14 validates :purchase_date 15 validates :expiry_date 16 validates :price 17 end 18 19 # 初期化メソッド 20 21 def initialize(attributes = {}) 22 super attributes 23 self.foods = FORM_COUNT.times.map { Food.new() } unless self.foods.present? 24 end 25 26 def foods_attributes=(attributes) 27 self.foods = attributes.map { |_, v| Food.new(v) } 28 end 29 30 def save 31 is_success = true 32 ava_count = 0 33 Food.transaction do 34 self.foods.each do |food| 35 food.valid? 36 if food.availability 37 f = Food.new(box_id: box_id) 38 food.box_id = f.box_id 39 is_success = false unless food.save 40 ava_count += 1 41 end 42 end 43 if ava_count == 0 44 is_success = false 45 end 46 raise ActiveRecord::RecordInvalid unless is_success 47 end 48 49 rescue 50 p 'error' 51 ensure 52 return is_success 53 end 54end
自分で調べたことや試したこと
仮説
fields_forを用いると、欄への記載に関わらず「生成された入力欄が全てサーバーサイドに送られる」ため、カテゴリidが希望のレコードに付与されない?
ただし、もしそうであれば、その他の入力項目も正しく保存されないはずだが、jQueryで取得したカテゴリidのみ、おかしな挙動をしている。
長文かつ分かりにくい箇所があるかと思いますが、何卒よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/05/15 13:49