ruby-on-railsrubyrails-models

Assign user model to one of two models?


I have a user model that I want to assign to be teacher or student( teacher and student are two separated model ) because if the user signup he would have different registration fields depending on if he is teacher or student. User can be a teacher or student, not both.

I have tried, but don't think that this is the best way to do it. Any help?

class User < AR
  has_secure_password

  has_one :teacher, class_name: "teacher", foreign_key: "teacher_id", conditions: { role: 'teacher' }
  has_one :student, class_name: "student", foreign_key: "student_id", conditions: { role: 'student' }

  enum role: [:teacher, :student]
end

class Teacher < AR
  belongs_to :user, class_name: "user", foreign_key: "user_id"
end

class Student < AR
  belongs_to :user, class_name: "user", foreign_key: "user_id"
end

Solution

  • This is how you can implement the STI for your case

    class User < AR
      has_secure_password
    
      # Make all forms with User data send params with ':user' as a param key
      # instead of ':user_teacher'/':user_student'
      def self.model_name
        ActiveModel::Name.new(self, nil, 'User')
      end
    end
    
    class Teacher < User
      # custom methods 
    end
    
    class Student < User
      # custom methods
    end
    

    This way, you can have your form with form_for @user do # ....

    One caveat, it is all placed in the Single table in the DB (hence the name Single Table Inheritance), and that means a lot of NULL values for the unrelated fields (say Teacher has a teacher_identification_number, and a user has student_identification_number which are different in size or they require different validation) for all the Students that attribute teacher_identification_number would be NULL, and vice-versa.

    If the fields are much different between the two models, then you can analyze your data and put it in the different table to which only the Teacher/Student would have access to, that is called a Database Normalization (say Teacher has_many ClassInfo's or has_one JobInfo; or Teacher has_one TeacherProfile, and Student has_one StudentProfile or whatever).

    It all really depends on how you model your DB.

    References:
    - Blog Post - Medium - STI
    - Video Link - Drifting Ruby - STI
    - Video Link - @ RailsCasts - STI
    - Blog Post - StudyTonight - DB Normalization