Rails嵌套形成多对多特殊情况

时间:2013-08-27 19:52:29

标签: ruby-on-rails forms nested-forms

让我们考虑一下Rails中多对多模型的经典实现。

class Order
  has_many   :order_products
  has_many   :products, through: order_products
  accepts_nested_attributes_for :order_products
end

class Product
  has_many :order_products
  has_many :orders, through: order_products
end

class OrderProduct
  belongs_to :order
  belongs_to :product
  accepts_nested_attributes_for :products
end

<%= form_for(@order) do |f| %>
  <% f.fields_for :order_products do |op|%>
  <%= op.label :amount %><br>
  <%= op.text_field :amount %>

  <% op.fields_for :product do |p|%>
     <%= p.label :name %><br>
     <%= p.text_field :name %>
  <% end %>
<% end %>

问题出在我的情况下,我有一个完整的常数表产品,带有预定义的产品组。我需要在订单的创建/编辑视图中显示产品的所有列表,并且用户应设置他需要的每个产品的数量,无法添加其他产品。 order_products 是一个联接表。

在经典示例中,用户可以自己添加/删除产品到产品表,在我的情况下,他只能从预定义的集合中选择所需的产品,并且他的选择应记录在 order_products中表。

以上代码是针对经典案例给出的,我不知道如何将其与我的案例相符。

感谢您的帮助。

附录: 以下是我现在的代码

<%= form_<%= form_for(@order) do |f| %>
  <% f.fields_for :order_products do |op|%>
  <%= op.label :amount %><br>
  <%= op.text_field :amount %>
  <%= op.label :product_id, "Product" %>
  <%= op.select :product_id, Product.all.collect { |p| [p.name, p.id] } %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

我必须将以下代码添加到订单控制器中,以便创建所有未包含的产品以订购0金额,以便所有这些产品都在表单上。这不是最好的方法,你知道如何正确地做到这一点吗?

Product.all.each { |p| order.orderproducts.push(OrderProduct.new(:product_id => p.id,:order_id => 1, :amount => 0)) if !@order.orderproducts.any?{|b| b.product_id == p.id}}

1 个答案:

答案 0 :(得分:2)

好像您需要amount上的OrderProduct列/属性,并且您可以删除该类上的嵌套产品声明。

然后,您可以从订单中创建OrderProduct个实例,指定您想要的产品和该产品的数量。您不需要任何产品嵌套,因为您已经创建了产品。

然后你的表格会变成:

<%= form_for(@order) do |f| %>
  <% f.fields_for :order_products do |op|%>
  <%= op.label :amount %><br>
  <%= op.text_field :amount %>
  <%= op.label :product_id, "Product" %>
  <%= op.select :product_id, Product.all.collect { |p| [p.name, p.id] } %>
<% end %>

还应该为OrderProduct添加验证,以确保amount是有效的,正整数。

validates_numericality_of :amount, 
    :only_integer => true, 
    :greater_than_or_equal_to => 0