質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

jQueryの動的フォームで追加した値を全て保存したい

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 267

score 1

前提・実現したいこと

プログラミング初学者です。よろしくお願いします!
RailsとjQueryを使った実装にて、動的フォーム(jQuery)で追加したフォームを、Railsを通してデータベース(MySQL)に全て保存したいです。

(料理の味付け法を共有するサイトを作っています。ややこしいのでレシピサイトのようなものと同じと考えてくださって大丈夫です)

発生している問題・エラーメッセージ

エラー文はconsole、ターミナルともに起こっていません。
データベースへの保存のみ出来ていません。

該当のソースコード

コントローラー tastes_controller

class TastesController < ApplicationController
  def index
    @taste = Taste.all
  end

  def new
    @taste = Taste.new
    # @taste.build_seasoning
    # @taste.seasonings.build
    #親モデルとアソシエーションを組んでいる子モデルのインスタンスを生成
  end

  def create
    # @taste = Taste.new(taste_params)
    # if @taste.save
    # redirect_to root_path
    @taste = Taste.create(taste_params)
    if @taste.save
      redirect_to root_path
     else
       render :new
     end
  end

  private

  def taste_params
    params.require(:taste).permit(:title, :example, :image, :genre_id, seasoning_attributes: [:seasoning_name, :quantity]).merge(user_id: current_user.id)
  end
end


モデル taste.rb

class Taste < ApplicationRecord
  has_one_attached :image
  belongs_to :user
  has_one :seasoning
  accepts_nested_attributes_for :seasoning, allow_destroy: true
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :genre

  with_options presence: true do
    validates :image
    validates :title
    validates :example
    validates :genre_id, numericality: { other_than: 1 }
    validates :user_id
  end

end


モデル seasoning.rb

class Seasoning < ApplicationRecord
  belongs_to :taste, optional: true
end


ビュー new.html.erb

<%= render "/shared/header" %>

<div class="inner-contact">
    <div class="contact-form">
        <%= form_with(model: @taste, local: true) do |f| %>
         <%#エラーメッセージの表示 %>
          <%= render "shared/error_messages", model: f.object, class: "error-messages" %>
           <div class= "form">
             <div class="form_left">
                <div class="weight-darkcyan-text">
                     テイスト名
                  </div>
                <%= f.text_area :title, class:"taste_title", placeholder:"例) 濃厚ケチャップ味" %>
                <div class="weight-darkcyan-text">
                     使用例の料理写真
                 </div>
                <%= f.file_field :image, class:"taste_image" %>
                  <div class="weight-darkcyan-text">
                   おすすめジャンル
                  </div>
                <%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"select-box", id:"create-hour"}) %> 
                  <div class="weight-darkcyan-text">
                       作った料理
                  </div>
               <%= f.text_field :example, class:"how_to_cooks", placeholder:"例) 唐揚げ" %>
             </div>
             <div class="form_right">
               <%= f.fields_for :seasoning, @taste.build_seasoning do |seasoning| %>
                  <div class="seasoning_field" id="seasoning_field[0]">
                     <%= seasoning.text_field :seasoning_name, class:"seasoning_name", placeholder:"例) 醤油", name:"seasoning_name[0]", id:"seasoning_name[0]" %>
                     <%= seasoning.text_field :quantity, class:"quantity", placeholder:"例) 大さじ2", name:"quantity[0]",id:"quantity[0]" %>
                  </div>
                  <%= f.button '+', id: "add_btn", type: "button" %>
               <% end %>
             </div>
           </div>
          <%= f.submit "submit", class:"form-btn semibold" %> 
        <% end %> 
    </div>
</div>

<%= render "/shared/footer"%>


JS taste.js

 $(function(){
   // フォームカウント
   var frm_cnt =0;
   // クローンする
   $('#add_btn').on('click', function(){
     var original = $('#seasoning_field\\[' + frm_cnt + '\\]');
     var originCnt = frm_cnt;

     frm_cnt++;

     original
     .clone()
     .appendTo(original)
     .attr('id', 'seasoning_field[' + frm_cnt + ']')
     .end()
     .find('input, text_field').each(function(idx, obj) {
        $(obj).attr({
          id: $(obj).attr('id').replace(/\[[0-9]\]+$/, '[' + frm_cnt + ']'),
          name: $(obj).attr('name').replace(/\[[0-9]\]+$/, '[' + frm_cnt + ']')
         });
         $(obj).val('');
       });
  });
});

試したこと

いろいろいじってた結果、こちらの記述を変更した時のみデータベースへの保存が可能になりました。(レコード一つのみでしたが,,,)

<%= f.fields_for :seasoning, @taste.build_seasoning do |seasoning| %>
                  <div class="seasoning_field" id="seasoning_field[0]">
                     <%= seasoning.text_field :seasoning_name, class:"seasoning_name", placeholder:"例) 醤油", name:"seasoning_name[0]", id:"seasoning_name[0]" %>
                     <%= seasoning.text_field :quantity, class:"quantity", placeholder:"例) 大さじ2", name:"quantity[0]",id:"quantity[0]" %>
                  </div>
                  <%= f.button '+', id: "add_btn", type: "button" %>
               <% end %>


↑こちらのname属性の、name:"seasoning_name[0]"とname:"quantity[0]"を削除した場合、最下層に追加した値のみ、データベースへ保存されました。

ちなみコンソール上ではformの追加はされてるように見受けられます。
https://gyazo.com/61550f3891bd44baf2c3d16ce9b6254a

補足情報(FW/ツールのバージョンなど)

Ruby on Rails 6
DBはMySQLを使用しています。

自己分析

binding.pryでtaste_paramsを確認。
taste_params[:quantity]で確認するとnilに、、
seasoningsテーブルへの保存処理に問題あり?

  • コントローラーとモデルの確認
  • おあとjQueryの記述方が正しいか、学習も兼ねて復習。(特にname属性について)
    13: def create
 => 14:   binding.pry   
    15:   @taste = Taste.create(taste_params)
    16:   if @taste.save
    17:     redirect_to root_path
    18:    else
    19:      render :new
    20:    end
    21: end


[1] pry(#<TastesController>)> taste_params[:quantity]
=> nil
[2] pry(#<TastesController>)> taste_params[:title]
=> "濃厚ケチャップ味"

自己分析追記
テーブル設計の問題かと思い、アソシエーションの確認。
初期では1対1で考えていたが、レコードを複数保存すると考えると1対多では?と思い、テーブル、アソシエーションを修正。状況変わらず。
そもそもname属性がなくてもformの追加ができている→nameではないもので値を取得している?
怪しいのはid?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る