0
votes

Rails app using Devise for user authentication. Started simple, now getting quite complex.

There are 3 kinds of user that will be logging in to the site: Admin, Teacher, Parent. I have a single Devise User model and User.role string for these. There is a Student model (which doesn't log in) and a Lesson model.

These are the relationships I need:

  • Lesson belongs to one Student
  • Student has many Lessons
  • Student has many Teachers
  • Student belongs to one Parent
  • Parent has many Students
  • Teacher has many Students

Basic functionality of the site: Teachers log in and make lessons for their students. Parents log in and see all lessons for their kids (students). Admins log in and can CRUD teachers, parents and students.

I have most of it working but got stumped when I tried to implement 'student has many teachers' and 'parent has many students'. My initial (incorrect) assumptions were that a student only has one teacher and that a parent just has one child at the school.

So it seems that using a User.role string won't suffice for these relationships.

Any advice or general concepts would be greatly appreciated.

3

3 Answers

0
votes

Are you just looking for a join table, ie a has_and_belongs_to_many relation?

http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

As I see it:

class Student
  belongs_to :parent
  has_and_belongs_to_many :teachers
end

class Parent
  has_many :students
end

class Teacher
  has_and_belongs_to_many :students
end
0
votes

There can be multiple ways of solving this, what i understand is that you have solved this much but you have made things bit complex.

you can simply have 1 model `User' and remaining things can be polymorphic. You can move the common attributes in User and separate the remaining in their corresponding models.

It would be much better if had a look at code.

Thanks

0
votes

I ended up creating a third model and using has_many :through => to link everything together. I wanted to keep a single Devise user model and use a .role for authorization.

The third model I created was Timeslot, which is essentially where a teacher and student interact. Ideally I would have called it class or session but they're both reserved words.

# timeslot.rb
class Timeslot < ActiveRecord::Base
  belongs_to :user
  belongs_to :student
end

# user.rb
class User < ActiveRecord::Base
  ROLES = %w[admin teacher parent]
  has_many :timeslots
  has_many :students, through: :timeslots
end

# student.rb
class Student < ActiveRecord::Base
  has_many :lessons
  has_many :timeslots
  has_many :users, through: :timeslots
end

This allows a user with a teacher role to have many students and vice-versa. The Student model has a parent_id column which stores the id of the user with role parent. That part is still a bit clunky but it works fine for now. I'm sure I'll have to refactor to something more elegant if the app has to scale.