Search code examples
ruby-on-railsactiverecordpolymorphic-associationssingle-table-inheritance

How to handle master-detail with STI


If role is an STI table:

class Role< ActiveRecord::Base
   self.inheritance_column= :role_type 
end

And Student & Counselor inherit Role:

class Student< Role
end

class Counselor< Role
end

And StudentDetail keeps extra information about one student:

class StudentDetail< ActiveRecord::Base
    belongs_to :student
end

And a user can be both student and counselor:

class User< ActiveRecord::Base
    has_many :roles
    has_one :student
    has_one :counselor
end

And number is a column in StudentDetail, And role_id is a column in StudentDetail

Is it possible to get the following syntax to work?

User.first.student.number

Meaning: "if Role table has one student with user_id == User.first.id then User.first.student is not null and if StudentDetail has role_id== Student.where("user_id= ?", User.first.id).first.id, make "student" act as a StudentDetail record and get the number field."


Solution

  • You will have the indirection User.first.student.student_detail.number out of the box. I don't think this hurts much :-)

    I see two options (at least) how to go further:

    • Define methods for the StudentDetail methods in Student:

      def number
        self.student_detail ? self.student_detail.number : nil
      end
      
    • Use method missing to do that automatically:

      def method_missing(name, *args, &block)
        self.student_detail ? self.student_detail.send(name, *args, &block) : nil
      end