1

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 %>
4

1 に答える 1

2

そして、これは、関連付けを介した has_many とフィールドを動的に追加するための繭宝石を使用した、ネストされたフォームフィールドに対する現在の実用的なソリューションです。私はまだこの特定のシナリオに合わせて調整を行っていますが、モデルと関連付けはうまく機能しています。

モデル:

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

Twitter ブートストラップに一部が混在するフォーム フィールド:

    <%= form_for @recipe, :html => { :class => 'form-horizontal' } do |f| %>
  <div class="control-group">
    <%= f.label :name, :class => 'control-label' %>
    <div class="controls">
      <%= f.text_field :name, :class => 'text_field' %>
    </div>
  </div>
  <div class="control-group">
    <%= f.label :description, :class => 'control-label' %>
    <div class="controls">
      <%= f.text_area :description, :class => 'text_area' %>
    </div>
  </div>

<%= f.fields_for :ingredients do |ff| %>
<%= render 'ingredient_fields', f: ff %>

<% end -%>

  <div class="form-actions">
    <%= link_to_add_association 'Add an Ingredient', f, :ingredients, :class => 'btn btn-  primary'%>
    <%= f.submit nil, :class => 'btn btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                recipes_path, :class => 'btn' %>
  </div>
<% end %>

そして、一致する部分的な _ingredient_fields.html.erb

   <div class="control-group">
    <%= f.label :name, :class => 'control-label' %>
    <div class="controls">
      <%= f.text_field :name, :class => 'text_field' %>
    </div>
  </div>
  <div class="control-group">
    <%= f.label :unit, :class => 'control-label' %>
    <div class="controls">
      <%= f.text_field :unit, :class => 'text_field' %>
    </div>
  </div>
  <%=link_to_remove_association "Remove Ingredient", f%>

  <%= render 'quantity_fields', f: ff %>
<% end -%>

レシピコントローラーに変更はありません。ネストされたフォーム要素を動的に追加および削除する機能が必要な場合は、cocoon gem (http://github.com/nathanvda/cocoon) を強くお勧めします。

乾杯!

于 2012-10-25T20:10:12.283 に答える