Rails Single Table Inheritance

Ruby on Rails supports Single Table Inheritance. Single Table Inheritance allows you to have one single SQL table, such as an employees table, manage different type of employees like managers and developers. A manager would normally have more responsibilities than a developer and you can separate these additional responsibilities in a different ActiveRecord model class.

Here is another example of Single Table Inheritance that you might find useful. You might have to support a hierarchy of users for you web application, such as User, Editor, and Administrator. An Administrator might have full Create, Read, Update, and Delete (CRUD) access while a User might just have read access. For this hierarchy of users you will need to create a Ruby class for each type and place it in the Rails app/models directory. Here is the base User class:

class User < ActiveRecord::Base
end

My Editor class:

class Editor < User
end

And the Administrator class:

class Administrator < Editor
end

Place each of these classes in their own Rails model file under the app/models directory.

To indicate to Ruby on Rails that the users table needs to support Single Table Inheritance you need to add a column named ‘type’ to the users table. Here is my users table definition:

CREATE TABLE users (
   id INT NOT NULL AUTO_INCREMENT,
   user VARCHAR(15) NOT NULL UNIQUE,
   pass VARCHAR(40) NOT NULL,
   type VARCHAR(20) NOT NULL,
   PRIMARY KEY (id)
);

In the column named type you should store the name of the class, the class type, that should be used for each user. To mark an certain user as an admin set his type to ‘Administrator’. By setting a user’s type to ‘Administrator’ you are giving him full administrator privileges as defined in your Administrator model class.

And now, in your controller you can look up all users that are administrators by using the following bit of code:

allAdmins = Administrator.find(:all)

If you want to look up all known users you can do so by using the User class as in the following snippet of code:

allUsers = User.find(:all);

At this point, you would add additional responsibilities to editors and administrators by adding methods to those model classes.

Enjoy. Share. Be Happy.
  • Twitter
  • Facebook
  • StumbleUpon
  • del.icio.us
  • Tumblr
  • Google Bookmarks
  • FriendFeed
  • Yahoo! Buzz
  • Reddit
  • Digg
  • HackerNews
  • Suggest to Techmeme via Twitter
  • LinkedIn
  • Ping.fm
  • Identi.ca
  • Mixx
  • Furl

Related posts:

  1. Hear Me Ro(a)R
  2. Acts As Voteable Rails Plugin
  3. Acts As Bookmarkable Plugin
  4. Rails Acts As Authenticated Plugin
  5. Acts As Commentable Plugin

This entry was posted in Programming, Ruby, TechKnow. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

11 Comments

  1. Kapslok
    Posted April 1, 2007 at 10:48 pm | Permalink

    A quick question: would you still have controllers for Administrator, Editor and User, or just a single one for User? This stuff is confusing. Is it possible to have an ActiveRecord model inherit from another ActiveRecord model – so as an example you extend the original User model with additional fields in a Editor model?

    On a side note:
    Your db table definition will restrict you user.type to 10 characters, so your example of specifying ‘Administrator’ will fail.

  2. Posted April 2, 2007 at 3:35 pm | Permalink

    @Kapslok – Yes, an Administrator model can extend the User model. The name of the database table would be users. The users table would store both administrator and regular end users.

    In general, a model can extend from any other model or from ActiveRecord directly. The name of the database table would be the plural of the class that extends ActiveRecord directly.

    A model does not have to be paired with a controller so you don’t have to have a controller for each model.

    Thanks, for letting me know about the the column type being 10 character wide. I originally named the administrator class Admin.

  3. Posted August 10, 2007 at 6:50 am | Permalink

    Thanks for this, I’ve been doing some rather confusing Single Table Inheritance stuff for the first time recently, and this has been (and will continue to be) a very good resource.

  4. Posted December 14, 2007 at 10:24 am | Permalink

    Crisp, clear and to the point. Ever thought of writing for the RoR Wiki? ;)

  5. Posted November 27, 2008 at 1:35 am | Permalink

    thank’s for the explain

    i just realize STI in ruby on rails is very simple, and the part i like is, it don’t need to create additional table, just create additional model

  6. LG
    Posted March 23, 2009 at 12:45 pm | Permalink

    It looks like to_xml does weird stuff with STI. Consider

    user = User.find(3)
    puts user.class

    This gives Administrator as above. However, then do

    user.to_xml

    It comes back looking like:

    Barb

    I want to have the outer XML wrapper still be and have administrator inside the XML as a or something. Any way to do that without writing a substitute to_xml function?

    TIA

  7. Posted March 23, 2009 at 11:03 pm | Permalink

    Hi. Thanks for the post.

    One point: Shouldn’t your Administrator model inherit from User? It is inheriting from Editor in your example.

  8. don
    Posted March 26, 2009 at 4:24 am | Permalink

    The Administrator model can inherit from either Editor or User. If it inherits from Editor, it has all of the privileges of Editor, so it makes more sense to inherit from it.

  9. Pratik
    Posted June 7, 2009 at 4:06 pm | Permalink

    Thanks for the information. Can i create a separate table for Administrator and Editor if i want to store custom attributes. I mean the attributes for Administrator and Editor which are not generic and cannot be fitted into the User model.

  10. Jolmash
    Posted June 13, 2009 at 3:33 pm | Permalink

    I have some question, I’d thank you guys if you can help me, I have the same question than Pratik: how do you handle custom attributes for each role? I wouldn’t like to have one table per role. another question is: could the type column be replaced by a dynamic attribute in the model? thanks in advance

  11. Cookie
    Posted July 21, 2009 at 3:04 am | Permalink

    Can we put all the inherited models in the same file along with the parent class? When I try to do model.singularize.classify.constantize, I get a “Uninitialized contant model”. Weird thing is, it works okay on the console, but not when I run the app. Thanks

2 Trackbacks

  1. [...] 6. OO Inheritance (RoR supports Single Table Inheritance) – Rails Single Table Inheritance[...]

  2. By Geek Mama » Blog Archive » The TYPE Column on August 14, 2009 at 1:56 pm

    [...] to get the most out of your table relationships at guides.rubyonrails.org.  And I ran across a post by Techknow that does a great job of describing Single Table [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*