Checkboxes in forms for Rails

Imagine we are creating a web application to help a conference coordinator organize and confirm which attendees will attend which sessions. This can be completed in Rails using collection select boxes.

Defining the Models

Let’s first create the models and associations between sessions and attendees.

1
2
3
4
class Session < ActiveRecord::Base
  has_many :session_attendees
  has_many :attendees, through: :session_attendees
end
1
2
3
4
class Attendee < ActiveRecord::Base
  has_many :session_attendees
  has_many :sessions, through: :session_attendees
end

We’ll next create the join model that associates sessions with attendees.

1
2
3
4
class SessionAttendee < ActiveRecord::Base
  belongs_to :session
  belongs_to :attendee
end

We can now establish that each session has many attendees and every attendee can have many sessions.

Generate the Form

Our coordinator wants to view a page that will create a new session and record all the attendees for that particular session. Assuming that the attendees’ information has already been entered into the database, we will list all of them on the page with checkboxes using the form_for helper method to create a form.

1
2
3
4
5
6
7
8
<%= form_for @session do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>
  <%= f.label :scheduled_time %>
  <%= f.text_area :scheduled_time %>
  <%= f.collection_check_boxes :attendee_ids, Attendee.all, :id, :name %>
  <%= f.submit %>
<% end %>

Let’s examine the colleciton_check_boxes method a little closer and the params that we are passing into it.

:attendee_ids: the collection of all attendee_ids that will be passed in if the particular checkbox is marked

Attendee.all: the collection of all possible checkbox options that will be displayed on the form

:id: the parameter of an attendee that will be passed into the attendee_ids collection

:name: the attribute of the attendee that will be visible next to the checkbox

The form will be rendered in HTML as:

1
2
3
4
5
<input type="checkbox" value="1" name="session[attendee_ids][]" id="session_attendee_ids_1" />
<label for="session_attendee_ids_1">Mr. Peabody</label>
<input type="checkbox" value="2" name="session[attendee_ids][]" id="session_attendee_ids_2" />
<label for="session_attendee_ids_2">Sherman</label>
<input type="hidden" name="session[attendee_ids][]" value="" />

Notice that a hidden input field is created, so that all the checkboxes can be left unchecked. After clicking submit, the params will be passed to the controller as a nested hash:

{:session => {:attendee_ids => ["1", "2", ""]}} 

Which brings us to the final step.

Whitelist the params in the Controller

To prevent CSRF attacks, we will add attendee_ids to the permitted params. Note: to permit a params attribute defined with an array, we must pass it in with an empty array:

params.require(:session).permit(:name, :scheduled_time, attendee_ids:[])

Our convention coordinator is now satisfied with a form that will create a new session and record all attendees who are well, attending.