Reputation: 649
Let consider the classic realization of many-to-many model in 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 %>
The problem is in my case I have a full constant tables products, with predefined set of products. I need to show all list of products on create/edit view of order and user should set amount of each product he needs, there is no way to add additional products. order_products is a join table.
In classic example, user by himself can add/delete products to products table, in my case he can only choose the needed product from predefined set and his choose should be recorded in order_products table.
The above code is given for classic case, I don't know how to fit it to my case.
I would appreciate your help.
Addendum: The following is the code that I have right now
<%= 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 %>
I had to add the following code to order controller, in order to create all non icluded products to order with 0 amount, such that all of them are on the form. It's not the best way, do you know how to do it correctly?
Product.all.each { |p| order.orderproducts.push(OrderProduct.new(:product_id => p.id,:order_id => 1, :amount => 0)) if [email protected]?{|b| b.product_id == p.id}}
Upvotes: 0
Views: 568
Reputation: 34774
Seems like you need an amount
column/attribute on OrderProduct
and that you can remove the nested products declaration on that class.
You can then create OrderProduct
instances from your order specifying the product that you want and the amount of that product. You don't need any nestedness for product because you have those created already.
Your form then becomes something like:
<%= 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 %>
It would also be worth adding a validation to your OrderProduct
to ensure that amount
is a valid, positive, integer.
validates_numericality_of :amount,
:only_integer => true,
:greater_than_or_equal_to => 0
Upvotes: 2