26

I'm making a form for an Order object, and the order has many Products, via a join table called OrderProducts. So, we've got something like this:

<% @order = Order.new %> <% form_for @order do |f| %> <% @products.each do |product| %> ... want to iterate over products here to build up "order[product_ids][]", with one checkbox per product <% end %> <% end %> 

Usually for each product i would have a check_box_tag, saying

<%= check_box_tag "order[product_ids][]", product.id, @order.product_ids.include?(product.id) %> 

But this, while working fine, always feels like a bit of a cop out. Is there a way i can do it with the f.check_box syntax? Important note - on the project in question I'm working in Rails 2.2.2, so a solution that works in rails 2 would be ideal.

2

4 Answers 4

44
+25

Rails <= 2.x (original)

<% @products.each do |product| -%> <% fields_for 'product[]' , product do |product_fields| -%> [...] <%= product_fields.check_box :id %> <% end -%> <% end -%> 

Rails >= 3.x (updated)

<% @products.each do |product| -%> <%= fields_for 'product[]' , product do |product_fields| -%> [...] <%= product_fields.check_box :id %> <% end -%> <% end -%> 
Sign up to request clarification or add additional context in comments.

5 Comments

I tried this and the html that is produced is <input checked="checked" id="product_5_id" name="product[5][id]" type="checkbox" value="1">. As you can see the name is "product[5][id]" whereas i need it to be "order[product_ids][]". Have i misunderstood your point? (btw it's .check_box not .checkbox)
I know it's too late but may be for others (as me): it should be nil instead of :id - <%= product_fields.check_box nil %>
Can't make a 1 character change, but the second line should start with <%= rather than <%
For what it's worth, I typically use the solution provided by Max Williams in the question itself, as it works in a wider variety of situations.
Doesn't seem to work with nil for rails 5 - undefined method `' for #<Class xxxxxx>
31

I know the author was looking for version 2 answers, but this is the top hit for google and I though I would update:

One can do this ( I'm using 4.0, don't know how far back it goes ):

<%= form_for @order do |form| %> <%= form.collection_check_boxes(:product_ids, Product.all, :id, :labeling_method ) %> <% end %> 

For more info: http://edgeapi.rubyonrails.org...

1 Comment

This doesn't work on Rails 3.2.13 and below: See: apidock.com/rails/v4.0.2/ActionView/Helpers/FormOptionsHelper/…
1

I've done a number of multi checkbox forms over the years and different Rails version. Rails has never provided any really clean way to do it, but the "cop out" solution you came up with is pretty good isn't it? It's one line, it's explicit, and as long as the list of products is reasonably short it will perform adequately.

To answer your specific question, f.check_box will never work for this. It's just short hand for the check_box_tag, but none of the semantics apply. If you want to go Rails native, the only possibility I think is to use nested attributes. Part of the problem is that there is not one obvious way for this type of thing to work. Rails core went through a lot of planning and feedback to come up with nested attributes as they exist, and though they seem a bit obtuse, they capture the most common use cases quite elegantly. But nested attributes were introduced in Rails 2.3, and besides they will introduce quite a bit of conceptual overhead for something which sounds like it doesn't need the complexity.

There are also some plugins that provide helpers for this, although I haven't used any in a long time (since Rails 2 era actually). My impression is that they too are overkill unless you have many forms that make use of this pattern.

In short, I think you should go ahead with your existing solution.

1 Comment

Thanks Dasil, i did :) It's always been something that's bugged me a little, though.
-1

formastic gem

check_boxes option is very good to implement multiple checkboxes

like

f.input :yourcolumn, :as => :check_boxes, :collection => your_collection 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.