Bick
Bick

Reputation: 773

Rails5 - Update join table with has_many :through : using fields_for

I have a trouble to update my join table course_students.

When I create a new student, I want to select a course from dropdown list(from two courses Course1 and Course2 which already saved in course table) and update course_students. And I want my couse_students table to be something like this.

 id | student_id | course_id |         created_at         |         updated_at         
----+------------+-----------+----------------------------+----------------------------

  1 |          1 |         1 | 2017-08-23 16:41:57.228094 | 2017-08-23 16:41:57.228094

Thanks to http://railscasts.com/episodes/17-habtm-checkboxes-revised?view=asciicast, I somehow found out the following code works for radio_button_tag. But there is an error wrong number of arguments when I change radio_button_tag to select_tag.

Also, I am not sure if this is the correct way because the information seems bit old. After some google search, I often found that people use field_for in new.html.erb, so I tried but I could not update course_students table.

In the future, I would like to add other columns like teacher, date_from, class_room, and something like that in course_students table.

I would really appreciate your help.

・models

class Student < ApplicationRecord
  has_many :course_students
  has_many :courses, :through => :course_students

  accepts_nested_attributes_for :course_students
end

class Course < ApplicationRecord
  has_many :course_students
  has_many :students, :through => :course_students

end

class CourseStudent < ApplicationRecord
  belongs_to :student
  belongs_to :course

end

・migrations

class CreateStudents < ActiveRecord::Migration[5.1]
  def change
    create_table :students do |t|
      t.string :first_name
      t.string :middle_name
      t.string :last_name

      t.timestamps
    end
  end
end

class CreateCourses < ActiveRecord::Migration[5.1]
  def change
    create_table :courses do |t|
      t.string :name

      t.timestamps
    end
  end
end

class CreateCourseStudents < ActiveRecord::Migration[5.1]
  def change
    create_table :course_students do |t|
      t.integer :student_id
      t.integer :course_id

      t.timestamps
    end
  end
end

・course table

id |     name     |         created_at         |         updated_at         
----+--------------+----------------------------+----------------------------
 1 | Course1 | 2017-08-22 20:03:46.226893 | 2017-08-22 20:03:46.226893
 2 | Course2    | 2017-08-22 20:03:46.228765 | 2017-08-22 20:03:46.228765

・student.controller, strong params.

  def student_params
    params.require(:student).permit(:first_name, :middle_name, :last_name, course_ids: [], date_froms: [] )
  end

・new.html.erb

<h1>Create new student</h1>
<%= form_for(@student) do |f| %>
    <%= f.label :first_name %>
    <%= f.text_field :first_name %>

    <%= f.label :middle_name %>
    <%= f.text_field :middle_name %>

    <%= f.label :last_name %>
    <%= f.text_field :last_name %>

    <%= Course.all.each do |course| %>
        <%= radio_button_tag "student[course_ids][]", course.id, @student.course_ids.include?(course.id), id: dom_id(course)%>
        <%= label_tag dom_id(course), course.name %>
    <% end %>

    <%= f.submit "Create new student", class: "btn btn-primary" %>
<% end %>

Upvotes: 2

Views: 577

Answers (2)

Ajinath  Jedhe
Ajinath Jedhe

Reputation: 180

Use nested_form_for instead of form_for and for course_students use field_for that nested form helper provide. https://github.com/ryanb/nested_form

<h1>Create new student</h1>

<%= nested_form_for(@student) do |f| %>
  <%= f.label :first_name %>
  <%= f.text_field :first_name %>

  <%= f.label :middle_name %>
  <%= f.text_field :middle_name %>

  <%= f.label :last_name %>
  <%= f.text_field :last_name %>

  <%= f.fields_for :course_students do |ff| %>
   <%= ff.hidden_field :student_id, value: @student.id %>
   <%= ff.collection_select :course_id, Course.all, :id, :name %>
  <% end %>

  <%= f.submit "Create new student", class: "btn btn-primary" %>
<% end %>

you needs to permit course_students params in controller like this:

def student_params
  params.require(:student).permit(:first_name, :middle_name, :last_name, course_students_attributes: [ :course_id, :student_id] )
end

Upvotes: 1

Bick
Bick

Reputation: 773

Found out that the following code worked!

students_controller

  def new
    @student = Student.new
    @student.course_students.build
  end

  private

  def student_params
    params.require(:student).permit(:first_name, :middle_name, :last_name, course_students_attributes: [ :course_id, :student_id] )
  end

new.html.erb

<%= f.fields_for :course_students do |ff| %>
  <%= ff.hidden_field :student_id, value: @student.id %>
  <%= ff.collection_select :course_id, Course.all, :id, :name %>
<% end %>

Thanks!

Upvotes: 0

Related Questions