Multi-select boxes in your rails view

It seems like, in current Rails, there’s not a very helpful helper around to give you select boxes which allow multiple items to be selected. So I present you with one:

  def collection_select_multiple(object, method,
                                 collection, value_method, text_method,
                                 options = {}, html_options = {})
    real_method = "#{method.to_s.singularize}_ids".to_sym
    collection_select(
      object, real_method,
      collection, value_method, text_method,
      options,
      html_options.merge({
        :multiple => true,
        :name => "#{object}[#{real_method}][]"
      })
    )
  end

And now it all works by magic — in my case the current categories that an article has are selected when the edit page comes up, and any changes are correctly saved back to the db. But it’s not nice enough. There’s still a lot of ugly code in the view. Let’s tidy things up by adding another helper:

  def collection_select_multiple_categories(object, method,
                                            options = {}, html_options = {})
    collection_select_multiple(
      object, method,
      Category.find(:all), :id, :title,
      options, html_options
    )
  end

Now the call in the view looks like:

<%= collection_select_multiple_categories :article, :categories %>

Ah, doesn’t that look much more like what we’re used to?

15 thoughts on “Multi-select boxes in your rails view

  1. Oh, beautiful :) I’m going to bookmark the post, the helper might be useful in a near future :) Thanks

  2. It’s a really well made piece of code ! :) Just a question: you use a Category.find(:all) in the code, by this way you need to create another helper if you’re using a collection that is different from Category.find(:all). Maybe isn’t better to add another arg to “collection_select_multiple_categories” ? Doing so you can specify time to time what is the collection you want to use.

  3. Sandro: That’s effectively what the first helper has become. You can call it along the lines of:

    <%= collection_select_multiple :article, :categories,
            Category.find(:all), :id, :title %>
    

    in your view and it will do the right thing. I just like the idea of taking as much as possible out of the view…

  4. When the name ends with “[]“, the html gets a warning from the tidy validator. Also, these names can’t be referenced in javascript as “[]” indicates array to js.

  5. dagny: Yeah, but that’s the rails idiom for these things. As for referencing them, don’t you use the id rather than the name? Rails does the right thing and, in my particular example, calls the id article_category_ids.

    FWIW, the W3C Validator doesn’t seem too fussed about the name having a ‘[]‘ in it.

  6. This doesn’t compile for me. I think

    collection_select( object, real_method, collection, value_method, text_method, options, html_options.merge({

    the above part should be as below

    collection_select( object, method, collection, value_method, text_method, options, html_options.merge({

    Also this doesn’t work on edit mode (doesn’t give preselected items hightlighted

  7. Hey cud u help me please.. I am a beginner for ruby on rails trying to develop a shopping cart cud u point me the rite tutorials which will help me understand things better Thanks..

  8. Hi Graeme,

    Thanks very much for this!

    But, with this method I can’t unselect all categories in the form — I mean, if I chose one previously, then I can’t unchose it (without choosing another one).

    Can you confirm this?

    And, if this is a bug, how would one go about fixing it?

    TIA

  9. ok, got it — it’s an option f select[xxx] methods

    thanks again f this great helper!

  10. The code for the view works very well but due to the fact that the attribute name is pluralised in my case its interest_id_ids I can’t seem to save the records to the particular model.

    Please help

  11. sir,

    i am having problems while using collection_select,i want to know how to use the selected value option in colletion select,heres my code :

    <%= collection_select(:template_1, :templates_id, Template.find(:all,:joins=>”right join user_templates on user_templates.template_id = templates.id inner join users on users.id = user_templates.user_id”,:conditions => “users.id=’#{session[:id]}’” ),:template_id, :TemplateTitle,{ :prompt => “Select Template”},{:name=>’template’,:style => “color: green”}) %>