Matt Elhotiby
Matt Elhotiby

Reputation: 44066

How do i handle checkboxes in a rails has_many?

Ok so i have data model

class Application < ActiveRecord::Base
  has_many :schedules

class Schedule < ActiveRecord::Base
 belongs_to :application
 belongs_to :time_slot
 attr_accessible :time_slot_id, :application_id, :day


class TimeSlot < ActiveRecord::Base
  attr_accessible :end_time, :friday, :name, :saturday, :start_time, :sunday, :thursday, :tuesday, :wednesday

Basically when someone fills out an application I have a calendar view prompting them to select which time slots for the days...For example I will have Tuesday listed with 4 time slots and the user can select none of all the slots.

My question is: IS there a way to create checkboxes for each of the time slots. So if the user picks 4 slots for wednesday and 3 slots for friday I can pass that with the params and create a new schedule record with the day, time_slot_id, and application_id.

This is what i have so far, I have the time slots displaying but not sure how to do the checkbox that create the new record

= form_for(@application) do |f|

  %tr
    - ['friday', 'saturday', 'sunday'].each do |day|
      %td
        - time_slots(day).each do |slot|
          %p{:style => "font-size: 12px;"}= "#{slot.name} (#{custom_time(slot.start_time)} - #{custom_time(slot.end_time)})"

Upvotes: 0

Views: 169

Answers (1)

jvnill
jvnill

Reputation: 29599

you can add a check_box_tag inside the time_slots block

- time_slots(day).each do |slot|
  = check_box_tag 'application[time_slot_ids][]', slot.id, f.object.time_slots.include?(slot)
  %p{:style => "font-size: 12px;"}= "#{slot.name} (#{custom_time(slot.start_time)} - #{custom_time(slot.end_time)})"

this will add a check_box for each timeslot. it will use the time_slot_ids method provided by has_many when you add a has_many :time_slots to the application model.

# application.rb
has_many :schedules
has_many :time_slots, through: :schedules

UPDATE: some gotchas.

when no timeslot is selected, you'd probably see that the form seems like it's not saving, you still get the old timeslots associated to the application. This is because no time_slot_ids is passed to the controller. to prevent this, you need to add

check_box_tag 'application[time_slot_ids][]', nil

before the #each block so it always sends something when no checkbox is checked.

one more thing you'd want to change is the part that checks if the timeslot is selected.

f.object.time_slots.include?(slot)

this will hit the database for each timeslot if the timeslots are not eager loaded. one thing you can do is add an instance variable that keeps the time_slot_ids of the current application and check it against the slot in the block

# controller
@time_slot_ids = @application.time_slot_ids

# view
@time_slot_ids.include?(slot.id)

Upvotes: 1

Related Questions