Rails 4 introduced collection_check_boxes

Updated . Posted . Visible to the public.

Starting from Rails 4.0, you can use a special form options helper called #collection_check_boxes. It behaves similar to #collection_select Show archive.org snapshot , but instead of a single select field it renders a checkbox and a label for each item in the collection.

= form_for @post do |form|
  = form.collection_check_boxes :author_ids, Author.all, :id, :name_with_initial

How generated form params look like

If you have authors with the IDs 1, 2 and 3, the check boxes above will be named like this:

<input type="checkbox" name="post[author_ids][]" value="1">
<input type="checkbox" name="post[author_ids][]" value="2">
<input type="checkbox" name="post[author_ids][]" value="3">
<input type="hidden" name="post[author_ids][]" value="">

Note the hidden input at the end. This is a trick that Rails uses so users can uncheck all the check boxes. If this hidden input wasn't there, the form param author_ids[] would be missing from the params entirely, and the list would not be set on your model.

In your Rails controller, this will create params like this:

{ 'post' => { 'author_ids' => ['1', '2', '3', ''] } }

Permitting array params in your controller

Note that you need some special syntax to whitelist an array-valued parameter in your controller.

This will not work:

params[:post].permit(:subject, :body, :author_ids)

In your server log you will see a line:

Unpermitted parameters: author_ids

You need to say this instead:

params[:post].permit(:subject, :body, :author_ids => [])

Also, you might need to remove the blank when processing the parameter. You can do so like this:

p = params...
p[:author_ids].reject!(&:blank?) # Remove Rails' blank collection item

Customizing the output

You can customize the output by passing a block. The block will be called with a special builder object that has a handful of special methods. See the complex example below.

form.collection_check_boxes :author_ids, Author.all, :id, :name_with_initial do |b|
   b.label { b.check_box }
   # or
   b.label(class: "my-#{ b.object.class.name.parameterize }", 'data-value': b.value) { b.check_box + b.text }
end

The return values of each call will be joined and returned. You may of course render HTML inside the block:

# _fields.html.haml

= form.collection_check_boxes :author_ids, Author.all, :id, :name_with_initial do |b|

  .my-checkbox-wrapper
    = b.label do
      = b.text
      = b.check_box

Radio buttons

There is also #collection_radio_buttons Show archive.org snapshot .

Dominik Schöler
Last edit
Dominik Schöler
Keywords
strong, params, strong, parameters
License
Source code in this card is licensed under the MIT License.
Posted by Dominik Schöler to makandra dev (2015-04-16 07:48)