accepts_nested_attributes_forを使った多対多モデルの重複保存を防ぎたい
受付中
回答 0
投稿
- 評価
- クリップ 0
- VIEW 1,382
前提・実現したいこと
Productモデル(多)、Quantityモデル(中間)、Ingredientモデル(多)があります。
Productモデルを保存する際に、中間モデルとなるQuantityモデル、多対多のもう1方の多モデルである、Ingredientモデルへの同時保存をさせたいのですが、
その際、Ingredientモデルではすでにある名前(:name)の場合は新しく登録せず、ない場合のみ登録するというようなことをしたいと考えています。
現状
現在の状況としては、Productモデルを更新するフォームを作成し、中間モデルとなるQuantityモデル、多対多のもう1方の多モデルである、Ingredientモデルへの同時保存ができる状態です。
しかし、名前(:name)が重複しても保存できてしまう状態です。
自分でやったこと
調べてみてfind_or_create_byをどこかで使用するとわかったので、
https://learn.co/lessons/has-many-through-forms-rails のサイトのCREATE NEW CATEGORYの項目を参考に以下の内容をProduct.rbに記述しました。
しかし、名前が重複されて保存される状態は変わらないです。
Product.rb
def ingredient_attributes=(ingredient_attributes)
ingredient_attributes.values.each do |ingredient_attribute|
ingredient = Ingredient.find_or_create_by(ingredient_attribute)
Quantity.ingredient << ingredient
end
end
以下、作成したコードとなります。
該当するコード
product.rb
class Product < ApplicationRecord
has_many :quantities
has_many :ingredients, through: :quantities
accepts_nested_attributes_for :quantities, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :ingredients
def ingredient_attributes=(ingredient_attributes)
ingredient_attributes.values.each do |ingredient_attribute|
ingredient = Ingredient.find_or_create_by(ingredient_attribute)
Quantity.ingredient << ingredient
end
end
end
quantity.rb
class Quantity < ApplicationRecord
belongs_to :product
belongs_to :ingredient
accepts_nested_attributes_for :ingredient, reject_if: :all_blank
end
ingredient.rb
class Ingredient < ApplicationRecord
has_many :quantities
has_many :products, through: :quantities
end
products_controller.rb
def detail
@product = Product.find(params[:id])
@photo = Photo.new
end
def update
@product = Product.find(params[:id])
if @product.update(product_params)
redirect_back(fallback_location: setting_detail_product_path(@product), notice: "更新できました")
end
end
private
def product_params
params.require(:product).permit(
quantities_attributes:[:id, :ingredient, :ingreident_id, :product_id, :unit, :amount, :_destroy,
ingredient_attributes:[:id, :_destroy, :ingreident_id, :name]
]
)
end
products/detail.html.erb
<%= simple_form_for @product do |f| %>
<%= link_to_add_association 'add ingredient', f, :quantities,
'data-association-insertion-node' => "#product-ingredients ol", 'data-association-insertion-method' => "append",
:wrap_object => Proc.new {|quantity| quantity.build_ingredient; quantity } %>
<div id="product-ingredients">
<ol>
<%= f.fields_for :quantities do |quantity| %>
<%= render 'quantity_fields', f: quantity %>
<% end %>
</ol>
</div>
<% end %>
products/_quantity_fields.html.erb
<li class="control-group nested-fields">
<div class="controls">
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.fields_for :ingredient do |quantity_ingredient| %>
<%= f.label :set_name, "name:" %>
<%= quantity_ingredient.text_field :name %>
<% end %>
<%= link_to_remove_association "remove", f %>
</div>
</li>
解決方法をご存知の方がいらっしゃればアドバイスいただけると大変嬉しいです。
よろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
まだ回答がついていません
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.22%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる