3

I have a rails4 app. At the moment my collection select only works if I select only one option. Below is my working code. I only have product form. Industry model is populated with seeds.rb. IndustryProduct is only use to connect the other 2 models.

I'd like to know what I have to change in the code to be able to choose more.

I saw some working examples with multiple: true option like (https://www.youtube.com/watch?v=ZNrNGTe2Zqk at 10:20) but in this case the UI is kinda ugly + couldn't pull it off with any of the sample codes. Is there an other solution like having more boxes with one option chosen instead of one box with multiple options?

models:

class Product < ActiveRecord::Base
  belongs_to :user
  has_many :industry_products
  has_many :industries, through: :industry_products
  has_many :product_features

  accepts_nested_attributes_for :industry_products, allow_destroy: true
  accepts_nested_attributes_for :product_features

  validates_associated :industry_products
  validates_associated :product_features
end

class Industry < ActiveRecord::Base
  has_many :industry_products
  has_many :products, through: :industry_products

  accepts_nested_attributes_for :industry_products
end

class IndustryProduct < ActiveRecord::Base
  belongs_to :product
  belongs_to :industry
end

_form.html.erb

<%= form_for @product do |f| %>
  <%= render 'layouts/error_messages', object: f.object %>
  ......
  <%= f.fields_for :industry_products do |p| %>
    <%= p.collection_select :industry_id, Industry.all, :id, :name %>
  <% end %>
  <%= f.fields_for :product_features do |p| %>
    <%= p.text_field :feature, placeholder: "add a feature", class: "form-control" %>
  <% end %>
  <%= f.submit class: "btn btn-primary" %>
<% end %>

products controller

def new
  @product = Product.new
  @product.industry_products.build
  @product.product_features.build
end

def create
  @product = current_user.products.new(product_params)
  if @product.save
    redirect_to @product
  else
    render action: :new
  end
end
......
def product_params
  params.require(:product).permit(....., industry_products_attributes: [:id, :industry_id, :_destroy], industries_attributes: [:id, :name], product_features_attributes: [:feature])
end
Sean Magyar
  • 2,360
  • 1
  • 25
  • 57

1 Answers1

5

Firstly, you could fix your first collection select by using it to set the industry_ids for the @product:

<%= form_for @product do |f| %>
  <%= f.collection_select :industry_ids, Industry.all, :id, :name %>
<% end %>

This will allow you to set the collection_singular_ids method, which exists for all has_many associations.

You'd have to back it up in the params method:

#app/controllers/products_controller.rb
....
def product_params
  params.require(:product).permit(.... industry_ids: [])
end

A lot more succinct than using nested attributes.


To get that "multiple" selection, you'll want to use the following:

<%= f.collection_select :industry_ids, Industry.all, :id, :name, {}, { multiple: true } %>

Tested & working enter image description here

--

You may also want to look at collection_check_boxes:

<%= f.collection_check_boxes :industry_ids, Industry.all, :id, :name %>
unom
  • 11,438
  • 4
  • 34
  • 54
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Rich, I tried this one (I guess your product_param code should be `(........{ industry_ids: []})`, but for some reason I only can choose more industry if I use command+click and the `product.industries` won't get saved: `product.industries => #` and `product.industries.first => nil` – Sean Magyar Feb 15 '16 at 22:04
  • What's the console log for the request? – Richard Peck Feb 15 '16 at 22:08
  • `industry_ids` shouldn't be in curly brackets – Richard Peck Feb 15 '16 at 22:09
  • If I do it like this: `....., industry_products_attributes: [:id, industry_ids: [], :_destroy]` then I get `syntax error, unexpected ']', expecting => ...d, industry_ids: [], :_destroy], industries_attributes: [:id...` , but if I use the { } then I get `Unpermitted parameter: industry_ids` – Sean Magyar Feb 15 '16 at 22:28
  • Nooooo, this is a replacement for nested attrs for `industry_products` :) – Richard Peck Feb 15 '16 at 22:29
  • You just need `params.require(:product).permit(:x, :y, industry_ids: [])` and it will automatically create the `insutry_products` you want without the nested attrs. You'll still need the nested attr for `product_features` – Richard Peck Feb 15 '16 at 22:29
  • I seeeee. It works! Thx a lot. The UI of this box can be changed somehow? I mean, can't you just highlight more options with simple clicks rather than command+click? – Sean Magyar Feb 15 '16 at 22:33
  • Are you using Windows / Mac / Linux? – Richard Peck Feb 15 '16 at 22:34
  • I'm using only mac at the moment – Sean Magyar Feb 15 '16 at 22:35
  • Hmmmmmmmmmmmmm I don't know... I mean it's a core OS thing whether the ui would have to be multi-select with crtl-click. I could look up on Google, I've never really dealt with it – Richard Peck Feb 15 '16 at 22:39
  • http://stackoverflow.com/questions/12585863/how-can-i-make-an-html-multiple-select-act-like-the-control-button-is-held-down – Richard Peck Feb 15 '16 at 22:40
  • Ohh, I see. I will check it out then! I thought it would be something like html option. Thanks for the help again! – Sean Magyar Feb 15 '16 at 22:41