Reputation: 153
The same Teacher can teach in different schools and different subjects,eg:
Dan teaches English and Math in the School A and Physics in the School B
I tried use a has many through between these 3 model, but i don't know how can i add many schools and many subjects in a specific Teacher
Here what i tried
class Teacher < ApplicationRecord
has_many :school_teacher_subjects
has_many :schools, through: :school_teacher_subjects
has_many :subjects, through: :school_teacher_subjects
end
class School < ApplicationRecord
has_many :school_teacher_subjects
has_many :teachers, through: :school_teacher_subjects
has_many :subjects, through: :school_teacher_subjects
end
class Subject < ApplicationRecord
has_many :school_teacher_subjects
has_many :teachers, through: :school_teacher_subjects
has_many :schools, through: :school_teacher_subjects
end
class SchoolTeacherSubject < ApplicationRecord
belongs_to :teacher
belongs_to :school
belongs_to :subject
end
What i want is that inside the Teacher New/Edit form, i can save one or many schools and one or many subjects in the database at same time in this way:
+----+------------+-----------+------------+
| id | teacher_id | school_id | subject_id |
+----+------------+-----------+------------+
| 1 | 2 | 2 | 4 |
| 2 | 2 | 2 | 1 |
| 3 | 1 | 3 | 2 |
| 4 | 1 | 3 | 6 |
+----+------------+-----------+------------+
But all I can do is:
+----+------------+-----------+------------+
| id | teacher_id | school_id | subject_id |
+----+------------+-----------+------------+
| 72 | 8 | 2 | 2 |
| 74 | 2 | | 2 |
| 75 | 2 | | 6 |
| 76 | 1 | 3 | |
| 77 | 1 | | 2 |
| 78 | 1 | | 6 |
+----+------------+-----------+------------+
Here what i'm doing:
my controller and form
def new
@teacher = Teacher.new
@schools = School.all.order(name: :asc)
@subjects = Subject.all.order(name: :asc)
end
def edit
@teacher = Teacher.find(params[:id])
@schools = School.all.order(name: :asc)
@subjects = Subject.all.order(name: :asc)
end
def create
@teacher = Teacher.new(teacher_params)
respond_to do |format|
if @teacher.save
format.html { redirect_to admin_teacher_index_path, notice: 'Escola criada com sucesso.' }
else
format.html { render :new }
end
end
end
def update
@teacher = Teacher.find(params[:id])
respond_to do |format|
if @teacher.update(teacher_params)
format.html { redirect_to admin_teacher_index_path, notice: 'Escola editada com sucesso.' }
else
format.html { render :edit }
end
end
end
private
def teacher_params
params.require(:teacher).permit(:full_name, :genre, :status, school_ids: [], subject_ids: [])
end
<div class="row mb-3">
<div class="col">
<%= f.label :school_ids, 'Escolas(s)' %>
<%= f.collection_select(:school_ids, @schools, :id, :name, {:include_blank => "Selecione uma ou mais"}, {:class => "multiple-select2 custom-select", multiple: true}) %>
</div>
</div>
<div class="row mb-3">
<div class="col">
<%= f.label :subject_ids, 'Disciplina(s)' %>
<%= f.collection_select(:subject_ids, @subjects, :id, :name, {:include_blank => "Selecione uma ou mais"}, {:class => "multiple-select2 custom-select", multiple: true}) %>
</div>
</div>
Upvotes: 0
Views: 37
Reputation: 3005
One of the problems you have is that a Teacher can teach many subjects at many schools, but in your form you are selecting schools and subjects independently. Schools and Subjects must be selected together. I don't think you can do it with two multiple selects and passing two arrays (school_ids and subject_ids). In fact, a teacher could teach a subject in two schools and this cannot be implemented with your form. You need a more complex form. I would do it in a form where you could dynamically add new lines (subjects and schools related) using cocoon gem.
Models
class Teacher < ApplicationRecord
has_many :school_teacher_subjects
has_many :schools, through: :school_teacher_subjects
has_many :subjects, through: :school_teacher_subjects
# NEW
accept_nested_attributes_for :school_teacher_subjects,
reject_if: :all_blank, allow_destroy: true
end
class School < ApplicationRecord
has_many :school_teacher_subjects
has_many :teachers, through: :school_teacher_subjects
has_many :subjects, through: :school_teacher_subjects
end
class Subject < ApplicationRecord
has_many :school_teacher_subjects
has_many :teachers, through: :school_teacher_subjects
has_many :schools, through: :school_teacher_subjects
end
class SchoolTeacherSubject < ApplicationRecord
belongs_to :teacher
belongs_to :school
belongs_to :subject
end
Controller
private
def teacher_params
# CHANGED
params.require(:teacher).permit(:full_name, :genre, :status,
:school_teacher_subjects_attributes => [ :school_id, :subject_id, :id, :_destroy ])
end
View (main form):
<Teacher fields (fullname, genre, status, etc)>
<.............................................>
<div class="row mb-3">
<div class="col">
<%= f.simple_fields_for :school_teacher_subjects do |sts| %>
<%= render 'sts_fields', f: sts %>
<% end %>
<%= link_to_add_association 'Add new class', f,
:school_teacher_subjects,
:partial => 'sts_fields',
:force_non_association_create => true,
:data => {"association-insertion-method" => "before", "association-insertion-node" => 'this'}
%>
</div>
</div>
View (partial form for subject and school) sts_fields.html.erb :
<div class="nested-fields">
<div class="row">
<div class="col-xs-2">
<%= link_to_remove_association 'Remove', f %>
</div>
<div class="col-xs-5">
<%= f.collection_select :subject_id, @subjects, :id, :name %>
</div>
<div class="col-xs-5">
<%= f.collection_select :school_id, @schools, :id, :name %>
</div>
</div>
</div>
Upvotes: 1