Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HABTM checkbox in a nested form

I am trying to implement a HABTM checkbox in a nested form.

Currently, I have 3 models. Subject, lesson and groups. The associations are as follows: Each subject has many lessons. Each lesson has and belongs to many groups.

Right now, I am trying to implement them all on a single creation and edit form. Such that a lesson is nested in the subject and for each lesson there is a list of group check boxes to implement the HABTM relationship.

I am facing trouble implementing the HABTM relationship as there are many lessons per subjects and I am not sure how I could distinguish between the different lessons.

To elaborate further, I am able to get the nested form working but I can't get the HABTM checkboxes to save to the right lessons. The following code sample is my HABTM checkbox implementation.

  <% Group.all.each do |group|%>
      <%= check_box_tag "subject[lessons_attributes[0]][group_ids][]", group.id, f.object.groups.include?(group) %>
      <%= group.group_index %>
  <%end%>

Currently, I have saved it to the first lesson using this line "subject[lessons_attributes[0]][group_ids][]".

However, the number of lessons vary and I am not too sure how I could determine the lesson "number", i.e. the bolded 0 in "subject[lessons_attributes[0]][group_ids][]". Such that I could save the groups to the correct lesson.

Any advice would be appreciated.

like image 774
Butter Beer Avatar asked Feb 14 '13 15:02

Butter Beer


2 Answers

For those working with Rails 4 and having the same question (as I had)

The Group.all.each loop in @Viktor Trón's answer is unnecessary: There's a new FormBuilder method, collection_check_boxes, which has been created just for that!

Your code would be:

<% form_for @subject do |form| %>
  ....
  <% @subject.lessons.each_with_index do |l, i| %>
     <%= form.fields_for :lessons, l do |lesson_fields|%>
        <%= lesson_fields.collection_check_boxes :group_ids, Group.all, :id, :group_index %>
     <% end %>
 <% end %>
<% end %>

You then have to add accepts_nested_attributes_for :lessons to your Subject model, and in your SubjectsController, change the subject_params method to "permit" nested params for lessons:

params.require(:subject).permit(..., lessons_attributes: [:id, group_ids: []])

In your SubjectsController, the create or update actions remain unchanged: @subject = Subject.create(subject_params) for instance, will create the Subject, the associated lessons and update their HABTM relationships to groups correctly (unless I made a mistake somewhere!).

like image 164
Olivier Lance Avatar answered Nov 14 '22 19:11

Olivier Lance


the best practice is to prebuild (a few) lesson object on the subject (that is the form.object), then you iterate over them to have per-lesson fields. if you use simple_form or formtastic, collection select via checkboxes is easy:

<% form_for @subject do |form| %>
  ....
  <% form.fields_for :lessons do |lesson_form| %>
    ...
    <% lesson_form.input :group_ids, :as => :check_boxes %>

if you wanna use check_box_tag, you should iterate through lessons with an index and substitute the index in your checkbox name:

<% form_for @subject do |form| %>
  ....
  <% @subject.lessons.each_with_index do |l, i| %>
     <% Group.all.each do |group|%>
        <%= check_box_tag "subject[lessons_attributes[#{i}]][group_ids][]", group.id, l.groups.include?(group) %>
        <%= group.group_index %>
     <% end %>
like image 22
Viktor Trón Avatar answered Nov 14 '22 19:11

Viktor Trón