I've got a Product model and I need to implement related products, so I thought a self reference is the best way to do it:
class Product < ActiveRecord::Base
has_many :related_product_associations, class_name: "RelatedProduct"
has_many :related_products, through: :related_product_associations, source: :related_product
end
class RelatedProduct < ActiveRecord::Base
belongs_to :product
belongs_to :related_product, class_name: "Product"
end
In products_controller:
params.require(:product).permit(..., :related_products, ...)
Questions: 1. Are my models/controller all right 2. How to make form for several related products.
I thought the forms may look something like this:
<%= f.collection_select :related_product, @products, :id, :name, include_blank: true %>
<%= f.collection_select :related_product, @products, :id, :name, include_blank: true %>
<%= f.collection_select :related_product, @products, :id, :name, include_blank: true %>
In products_controller:
@products = Product.all
Your goal is to submit an array of ids in this form related_product_ids=[1,2,3,4]
.
To do that, the param has to be named product[realted_product_ids][]. Unfortunately, you can't do this. The second param has to be a param
# Note this doesn't work
<%= f.collection_select 'related_product_ids[]', @products, :id, :name, include_blank: true %>
But, you can do this (with multiple)
<%= f.collection_select :related_product_ids, @products, :id, :name, {:selected => @product.related_product_ids, :include_blank => true}, {:multiple => true} %>
Or you can do this
<%- (1..4).each do |i| %>
<%= select_tag 'product[related_product_ids][]', options_for_select(@products.map{|p| [p.name, p.id]}, @product.related_product_ids[i]), :include_blank => true %>
<% end %>
You can also try it out with check boxes. Later, switching to dropdowns added dynamically shouldn't be too hard.
<%- @products.each do |product| %>
<%= check_box_tag 'product[related_product_ids][]', product.id, @product.related_product_ids.include?(product.id) %>
<%= product.name %>
<%- end %>