4

Rails 3.2.3 アプリでネストされたフォームをセットアップしました。正常に動作しています。モデルは次のとおりです。

class Recipe < ActiveRecord::Base
  attr_accessible :title, :description, :excerpt, :date, :ingredient_lines_attributes

  has_and_belongs_to_many :ingredient_lines
  accepts_nested_attributes_for :ingredient_lines
end

と:

class IngredientLine < ActiveRecord::Base
  attr_accessible :ingredient_id, :measurement_unit_id, :quantity

  has_and_belongs_to_many :recipes
  belongs_to :measurement_unit
  belongs_to :ingredient
end

上記のように、Recipe には複数の IngredientLines を含めることができ、その逆も可能です。

私が避けようとしているのは、IngredienLine テーブルでのレコードの重複です。

たとえば、recipe_1 では {"measurement_unit_id" => 1, "ingredient_id" => 1, "quantity" => 3.5} の IngredientLine が関連付けられていると想像してください。recipe_5 では IngredientLine 子フォームがユーザーによって同じ値でコンパイルされます。 、IngredientLine テーブルに新しいレコードは必要ありませんが、結合テーブルの新しい関連レコードだけが必要です。

現在、IngredientLines の保存と更新はネストされたフォーム ルーチンによって処理されるため、IngredientLine コントローラーはありません。私の Recipe コントローラーでさえ、単純で標準的です。

class RecipesController < ApplicationController
  respond_to :html

  def new
    @recipe = Recipe.new
  end

  def create
    @recipe = Recipe.new(params[:recipe])
    flash[:notice] = 'Recipe saved.' if @recipe.save  
    respond_with(@recipe)
  end

  def destroy
    @recipe = Recipe.find(params[:id])
    @recipe.destroy
    respond_with(:recipes)
  end

  def edit
    respond_with(@recipe = Recipe.find(params[:id]))
  end

  def update
    @recipe = Recipe.find(params[:id])
    flash[:notice] = 'Recipe updated.' if @recipe.update_attributes(params[:recipe])
    respond_with(@recipe)
  end

end

create私の推測では、 IngredientLineの標準的な動作を でオーバーライドするには十分なはずですが、find_or_createそれを実現する方法がわかりません。

しかし、注意すべきもう 1 つの重要な点があります。いくつかの IngredientLines が存在する子フォームの編集を想像してください。すでに IngredientLine テーブルに格納されている別の IngredientLine を追加すると、レールはもちろん IngredientLine テーブルに何も書き込むべきではありませんが、すでに親に関連付けられている子レコードと、リレーションを作成する必要がある新しい子レコードを区別し、結合テーブルに新しいレコードを書き込みます。

ありがとう!

4

3 に答える 3

2

レシピモデルでメソッドを再定義します

def ingredient_lines_attributes=(attributes)
   self.ingredient_lines << IngredientLine.where(attributes).first_or_initialize
end
于 2012-05-23T11:15:47.813 に答える
2

古い質問ですが、同じ問題がありました。Rails 4のstrong_parametersで:idをホワイトリストに追加するのを忘れていました。

例えば:

widgets_controller.rb

def widget_params
  params.require(:widget).permit(:name, :foos_attributes => [:id, :name, :_destroy],)
end

ウィジェット.rb

class Widget < ActiveRecord::Base
  has_many :foos, dependent: :destroy
  accepts_nested_attributes_for :foos, allow_destroy: true
end

foo.rb

class Foo < ActiveRecord::Base
  belongs_to :widget
end
于 2013-11-17T12:53:46.670 に答える
1

私は同様の状況に遭遇し、この回答でインスピレーションを得ました。つまり、時間を節約するまで、ネストされたモデルの重複について心配する必要はありません。

あなたの例に翻訳して、に追加autosave_associated_records_for_ingredient_linesしましたRecipe。あなたの直感が言ったように、反復しingredient_linesて実行します。find_or_create成分の行が複雑な場合、Yuri のfirst_or_initializeアプローチの方がすっきりしている可能性があります。

これはあなたが探している動作をしていると思います: ネストされたモデルは複製されませんが、共有モデルを更新するのではなく、モデルを編集すると新しいレコードが作成されます。孤立している可能性が高いですが、それが深刻な懸念である場合は、そのモデルに現在のモデルと一致する ID を持つingredient_linesモデルが 1 つしかない場合は、更新することを選択できます。recipe

于 2012-06-30T18:56:33.260 に答える