Rails/Active Record polymorphic association needed? - ruby-on-rails

I have 3 models, a School which has many Teachers and Students. The problem is that Students can belong to either a School or a Teacher, so theoretically they always belong to a School through association. How would I deal with this type of data structure in Rails/Active Record?
class School < AR::Base
has_many :teachers
has_many :students
end
class Teacher < AR::Base
belongs_to :school
has_many :students
end
class Student < AR::Base
belongs_to ???
end

This solution should work, but you I have a doubt about your introduction ; you say that "a teacher have many student". This sentences implies "a student has ONE teacher".
Maybe you should set an has_and_belongs_to_many association.
class School < AR::Base
has_many :teachers
has_many :students, :through => :teachers
end
class Teacher < AR::Base
belongs_to :school
has_many :students
end
class Student < AR::Base
belongs_to :teacher
belongs_to :school, :through => :teacher
end

Clearly you need polymarphic association, can be done as
class School < AR::Base
has_many :teachers
has_many :students, :as => :studentable
end
class Teacher < AR::Base
belongs_to :school
has_many :students
end
class Student < AR::Base
belongs_to :studentable
end
don't forget to add studentable_id and studentable_type to student model.

Related

Rails Has_one and has_many relationship

I have Teacher model:
class Teacher < User
has_many :categories, dependent: :destroy
has_many :grades, through: :categories
end
Grade model:
class Grade < ApplicationRecord
has_many :categories, dependent: :destroy
has_many :teachers, through: :categories
end
Category model:
class Category < ApplicationRecord
belongs_to :teacher
belongs_to :grade
end
Student model:
class Student < User
end
Now i want to set up relationship between Grade model and Student model
(student has_one grade and a grade has_many students) with through model Category.
How can i do this?
class Student < User
has_one: :grade
end
and
class Grade < ApplicationRecord
has_many :categories, dependent: :destroy
has_many :teachers, through: :categories
has_many :students, through: :categories
end
and
class Category < ApplicationRecord
belongs_to :teacher
belongs_to :grade
belongs_to :student
end
Does the above not work..? You should put what you have tried in your post if you have run into issues.
Join tables are for many-to-many relationships. Since a student only has one grade, it is a many-to-one relationship, not a many-to-many relationship.
You do not need (and shouldn't use) a join table for this.
Instead add a grade_id column to the students (users) table and setup the associations like this:
class Student < User
belongs_to :grade
end
class Grade < ApplicationRecord
has_many :students
end
Don't use any through associations to connect students with grades.

Association between 3 models

I would like a user be able to create a course(so it should belong to one user) and also be able to join another course that it haven't created by him.What is the proper associations between the course and the user ? I want to make the following model associations:
Class User < ActiveRecord::Base
has_many :courses
has_many :comments ,through: :courses
end
Class Course < ActiveRecord::Base
has_and_belongs_to_many :users #here i am not sure
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :courses
end
I think what you should be able to do something like:
Class User < ActiveRecord::Base
has_many :courses
has_many :course_users
has_many :subscribed_courses, through: :course_users, source: :course # I think you should be able to do foreign_key: :course_id, class_name: 'Course'
has_many :comments ,through: :courses
end
Class Course < ActiveRecord::Base
belongs_to :user
has_many :course_users
has_many :participants, through: :course_users, source: :user # I think you should be able to do foreign_key: :user_id, class_name: 'User'
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :courses
end
#course_users is a join table for courses and users
class CourseUser < ActiveRecord::Base
# inside here you could have several other connections e.g grade of a user in a course within this join model
belongs_to :user
belongs_to :course
end
If I'm understanding what you're saying - you need to have a third model - you can call it enrollment
For Course you would use belongs_to :user if each course is created as a user.
Your Enrollment model with have two HABTAM
Class Enrollment < ActiveRecord::Base
has_and_belongs_to_many :users
has_and_belongs_to_many :courses
end
(An Aside, if a course is going to be offered more than once, you'll have to add an additional model for each instance of the course and the enrollment will belong to that model, and not courses)

How to do `has_one: model, through: join_model` in JSONAPI::Resource

What's the preferred way to do has_one :model, through: join_model in a model resource? Usually JSONAPI::Resource expects model_id column on the table/model who owns the association. That does not exist if a join table/model is used.
You can actually just mention the has_many relationship, with no need to mention the through association.
So if you had this model structure:
class Teacher < ActiveRecord::Base
has_many :classrooms
has_many :students, through: :classrooms
end
class Student < ActiveRecord::Base
has_many :classrooms
has_many :teachers, through: :classrooms
end
class Classroom < ActiveRecord::Base
belongs_to :teacher
belongs_to :student
end
In your Teacher resource, all you'd need is has_many :students.
And likewise, in your Student resource, you'd need has_many :teachers.

Should this has_many :through relationship be polymorphic or not?

I have a many-to-many relationship setup for Teachers and Classrooms via has_many :through:
class Teacher < ActiveRecord::Base
has_many :classrooms, :through => :classroom_memberships
end
class Classroom < ActiveRecord::Base
has_many :students
has_many :teachers, :through => :classroom_memberships
end
class ClassroomMemberships < ActiveRecord::Base
belongs_to :teacher
belongs_to :classroom
end
Currently, Students can only belong to one Classroom:
class Student < ActiveRecord::Base
belongs_to :classroom
end
Now I have the need to track historical classroom memberships for students, creating a second many-to-many relationship for classrooms. So, while a student can only belong to one classroom at a time, I need to know that last year, student A belonged to classroom B.
I'm thinking I have two viable options:
1.) Make the classroom_memberships association polymorphic so I'd have a classroomable_id and classroomable_type that would point to either a teacher OR a student.
2.) Simplify things and add another foreign key to ClassroomMemberships called student_id, in which case, for a given row, either student_id OR teacher_id would have a value.
Which is the better option?
I would probably go the route of:
class Course < ActiveRecord::Base
# like "MATH 100"
has_many :sections
has_many :teachers, :through => :sections
end
class Term < ActiveRecord::Base
# like "Fall 2015"
has_many :sections
end
class Teacher < ActiveRecord::Base
has_many :sections
has_many :courses, :through => :sections
end
class Section < ActiveRecord::Base
# a course, in a term, taught by a teacher, with registered students
belongs_to :term
belongs_to :course
belongs_to :teacher
has_many :registrations
has_many :students, :through => :registrations
end
class Registration < ActiveRecord::Base
# a student in a specific section
belongs_to :section
belongs_to :student
end
class Student < ActiveRecord::Base
# a student's registrations are their course history
has_many :registrations
has_many :sections, through :registrations
end
As a start, since this is a fairly basic modeling of an educational system.
It sounds like maybe you want a ClassroomMembershipHistory model.
Something like
class ClassroomMembershipHistory < ActiveRecord::Base
belongs_to :student
belongs_to :classroom
end
with a year attribute, stored however is easiest to query for your use case.

Rails associations - how can I set up associations for different varieties of users?

I'm creating a web app which consists of schools, courses, students, and teachers.
A school can have many courses and a course has one teacher and many students.
The problem I am running into is that a single user could be a teacher of one course, but a student in another course (or even a student or teacher in a course in a different school). I don't want to create a model for teachers and a separate model for students because I would like to track all my users in one place. There is an enrollment table which lists which users are enrolled as students in a course.
I would like to do something like the following:
class School < ActiveRecord::Base
has_many :courses
has_many :students :through enrollments
has_many :teachers :through courses
end
class Course < ActiveRecord::Base
has_one :teacher
belongs_to :school
has_many :students :through enrollments
end
class User < ActiveRecord::Base
has_many :courses
has_many :schools
end
But if I have only a users table and not two separate students and teachers tables, this won't work.
Instead, I would have to do something like
class School < ActiveRecord::Base
has_many :users [that are teachers]
has_many :users :through enrollments [that are students]
end
How can I set up my model and associations to make this work?
Thanks.
Use inheritance.
Teachers and students are inherited from the users model. You can consult http://api.rubyonrails.org/classes/ActiveRecord/Base.html for further information. Be sure to create a "type" column or equivalent in your User table.
class User < ActiveRecord::Base
end
class Student < User
end
class Teacher < User
end
Rails will treat them individually, but they will still exist in the User table.Let me know if you need further assistance
I may have missed something, but it should work if you add the class_name to your relation with "User":
class School < ActiveRecord::Base
has_many :courses
has_many :students :through enrollments, :class_name => "User"
has_many :teachers :through courses, :class_name => "User"
end
class Course < ActiveRecord::Base
has_one :teacher, :class_name => "User"
belongs_to :school
has_many :students :through enrollments, , :class_name => "User"
end
class User < ActiveRecord::Base
has_many :courses
has_many :schools
end
Add a teachers_id column to courses and use belongs_to instead of has_one. Then add a class_name option.
class School < ActiveRecord::Base
has_many :courses
has_many :students :through enrollments
has_many :teachers :through courses
end
class Course < ActiveRecord::Base
belongs_to :teacher, :class_name => 'User'
belongs_to :school
has_many :students :through enrollments
end
class User < ActiveRecord::Base
has_many :courses
has_many :schools, :through enrollments
has_many :teachers, :through :courses
end

Resources