What you've got at the moment will work for the case of associating users with classrooms, but not teachers as well, since at the moment the table to associate the two models can only signify one type of relationship.
NB: Rails expects model names to be singular and without underscores i.e. ClassroomUser
instead of Classroom_Users
in your example.
To associate teachers with classrooms, one approach would be to create an extra joining model:
user.rb:
class User < ActiveRecord::Base
has_many :classroom_teachers
has_many :classroom_students
has_many :teaching_classrooms, through: :classroom_teachers
has_many :attending_classrooms, through: :classroom_students
end
classroom.rb:
class Classroom < ActiveRecord::Base
has_many :classroom_teachers
has_many :classroom_students
has_many :teachers, through: :classroom_teachers
has_many :students, through: :classroom_students
end
classroom_student.rb:
class ClassroomStudent < ActiveRecord::Base
belongs_to :student, class_name: 'User', foreign_key: 'user_id'
belongs_to :attending_classroom, class_name: 'Classroom', foreign_key: 'classroom_id'
end
classroom_teacher.rb:
class ClassroomTeacher < ActiveRecord::Base
belongs_to :teacher, class_name: 'User', foreign_key: 'user_id'
belongs_to :teaching_classroom, class_name: 'Classroom', foreign_key: 'classroom_id'
end
Rails normally works out what type of model relates to a field based on the name of the field, e.g. a users
field will link to a collection of User
models. With the above schema, Rails can't infer the types of the models from the names of the associating fields, since it doesn't know that a teacher
is an alias for a user
. To overcome this, the class_name
attributes define the model types of the joining fields.
For the same reason, Rails needs some guidance knowing what database key relates to which field, which is what the foreign_key
attribute is for.
And finally the migration:
class CreateClassroomUsers < ActiveRecord::Migration
def change
create_table :users do |t|
end
create_table :classrooms do |t|
end
create_table :classroom_students do |t|
t.belongs_to :user, index: true
t.belongs_to :classroom, index: true
end
create_table :classroom_teachers do |t|
t.belongs_to :user, index: true
t.belongs_to :classroom, index: true
end
end
end
Edit:
Alternatively, instead of using two joining models, you could add an extra field to the ClassroomUser
model that you originally had, describing the role of the user (e.g. an enum that can be either student
or teacher
). That would allow more roles to be added in the future and might be easier to query than my previous suggestion. For example, to check whether a user is a student or teacher you'd need only one query:
example_user.classroom_users
and could then check the role fields on the returned ClassroomUser
records. See this question for an example of that approach.