Rails が入れ子になったフォームを DB に格納する方法に問題があります。私は、3 つのモデル Recipe、Ingredient、IngredientRecipe (以下のコード) を作成したレシピ Web サイト (趣味) を設計しています。材料は、Recipe を介して has_many を介してアクセスされます。したがって、レシピには多くの材料を含めることができ、材料は多くのレシピに属することができます。さらに、 IngredientRecipe モデルは、レシピと材料のすべての組み合わせに固有の量を保持します。
私の問題は、データを入力するためのネストされたフォームを作成することではなく、DB に格納する方法です。私の現在のコードでは、新しいエントリごとに IngredienRecipe モデルに 2 つの行が生成されます。1 つはレシピと数量の組み合わせ用、もう 1 つはレシピの材料関係用です。ただし、各エントリが独自のレシピ、材料、および数量の組み合わせをリンクして、component_recipes テーブルに正確に 1 つの行を生成するように設定しようとしています。
私はこの問題に数日間悩まされているので、ヒントやコードスニペットは大歓迎です:-(
ここに私の現在のモデルがあります:
class Recipe < ActiveRecord::Base
attr_accessible :description, :name
attr_accessible :ingredients_attributes, :ingredient_recipes_attributes
has_many :ingredient_recipes
has_many :ingredients, :through => :ingredient_recipes
accepts_nested_attributes_for :ingredients
accepts_nested_attributes_for :ingredient_recipes
end
class Ingredient < ActiveRecord::Base
attr_accessible :name, :unit
has_many :ingredient_recipes
has_many :recipes, :through => :ingredient_recipes
end
class IngredientRecipe < ActiveRecord::Base
attr_accessible :quantity
belongs_to :recipe
belongs_to :ingredient
end
変更されたレシピ コントローラー:
#Modified controller function
def new
@recipe = Recipe.new
@ingredients = @recipe.ingredients.build
@ingredient_recipes = @recipe.ingredient_recipes.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: @recipe }
end
end
そしてform_forビューファイル
<%= form_for @recipe do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<%=f.fields_for :ingredients do |ff|%>
<div class="field">
<%= ff.label :name %><br />
<%= ff.text_field :name %>
</div>
<%= f.fields_for :ingredient_recipes do |fff| %>
<div class="field">
<%= fff.label :quantity%><br />
<%= fff.text_field :quantity %>
</div>
<% end -%>
<div class="field">
<%= ff.label :unit %><br />
<%= ff.text_field :unit %>
</div>
<% end -%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
OK、コードを何度も調べた後、最終的に問題に対するより良い解決策を思いつきました. 秘訣は、Recipe --> Ingredient --> JOIN table を介してモデルを互いに入れ子にすることにあります。私の現在のソリューションでは、まだ fields_for を動的に追加していませんが、このバージョンでは、recipes_controller を変更する必要はありません。他の誰かがこれにも苦労している場合に備えて、私のコードは次のとおりです。
class Recipe < ActiveRecord::Base
attr_accessible :description, :name, :ingredients_attributes
has_many :unique_recipes
has_many :ingredients, :through => :unique_recipes
accepts_nested_attributes_for :ingredients
end
class UniqueRecipe < ActiveRecord::Base
attr_accessible :quantity, :recipe_id, :ingredient_id
belongs_to :recipe
belongs_to :ingredient
end
class Ingredient < ActiveRecord::Base
attr_accessible :name, :unit, :unique_recipes_attributes
has_many :unique_recipes
has_many :recipes, :through => :unique_recipes
accepts_nested_attributes_for :unique_recipes, allow_destroy: true
end
<%= form_for @recipe, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.label :name, :class => %>
<%= f.text_field :name, :class => 'text_field' %>
<%= f.label :description, :class => 'control-label' %>
<%= f.text_area :description, :class => 'text_area' %>
<%= f.fields_for :ingredients do |ff| %>
<%= ff.label :name, :class => %>
<%= ff.text_field :name, :class => 'text_field' %>
<%= ff.label :unit, :class => %>
<%= ff.text_field :unit, :class => 'text_field' %>
<%= ff.fields_for :unique_recipes do |fff| %>
<%= fff.label :quantity, :class => %>
<%= fff.text_field :quantity, :class => 'text_field' %>
<% end -%>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
recipes_path, :class => 'btn' %>
<% end %>