0

I a modeling Users in my rails app

Student < User
Parent < User
Staff < User
User

Every entity has slightly different attributes. I was going to use STI but thinking there might be a better way to model this e.g. originally i had

User
--------
id #primary key
name #common
email #common
type [Student|Parent|Staff]
id      # Student only
school  # Student only
year    # Student only
title   # Parent only
work    # Parent only

i.e Instead I wanted to split this into multiple tables, A User table with all users, then joining via natural keys into user specific tables. Was planning to use NATURAL JOINS e.g. DB would look like

User
--------
id
name
email
type [Student|Parent|Staff]

Student
--------
id
school
year

Parent
-------
title
work

So how do I get active record to do a Natural Join of Student and User table

i.e. I want to be able to do something like

class Student < ActiveRecord::Base  
end           
# would create an entry in Student and User tables.
Student.create(name:'john',school:'green high') 
# get via field in User table and puts out field in Student table
student = Student.where(email:'a@a.com') 
puts student.school

Kinda look for something like http://viralpatel.net/blogs/hibernate-inheritance-table-per-concrete-class-annotation-xml-mapping/

P.S I am about to upgrade to Rails 4 if that makes a difference in syntax would like to know if there is any changes in rails 4 vs rails 3 for this kind of thing.

dboyd68
  • 1,104
  • 15
  • 33

1 Answers1

0

This is speculation, but as you've not received much feedback, let me detail how I'd do things:

--

STI

I would keep all entries in a single table and then extend through the classes (how STI's generally work in my experience with Rails)

I would therefore keep your original setup (keep it DRY), and have the following:

#app/models/user.rb
Class User < ActiveRecord::Base
   # fields:
   # id #primary key
   # name #common
   # email #common
   # type [Student|Parent|Staff]
   # school  # Student only
   # year    # Student only
   # title   # Parent only
   # work    # Parent only
end

#app/models/student.rb
Class Student < User
    remove_method "title"
    remove_method "title="

    remove_method "work"
    remove_method "work="
end

#app/models/parent.rb
Class Parent < User
    remove_method "school"
    remove_method "school="

    remove_method "year"
    remove_method "year="
end

#app/models/staff.rb
Class Staff < User
end

This will give you the ability to perform the following:

@student = Student.create(name: "x", school: "y")

Of course, a variety of attributes won't be populated, which lead me to look up this question: Hiding an attribute in an ActiveRecord model

Apparently, you can use the remove_method method to "hide" various attributes in different models. This will give you the ability, albeit as a little hack, to only populate the models with the right data

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • why remove when you can override and raise an error that is informative about the inheritance structure? This will be clearer a couple of years down the road, when a simple no method error will not be very useful. – pixelearth Aug 15 '14 at 08:56
  • Sure - I don't know to be honest. I've not done what I outlined above - just wanted to give a suggestion. You are right, perhaps you could further the answer with an explanation about raising exceptions for `nomethod` errors etc? – Richard Peck Aug 15 '14 at 08:57