Agile Tortoise

Greg Pierce’s blog

« Dynamics AX: Making .NET calls from inside AX      Case sensitivity »

Rails: flatten your content model with single-table inheritance and alias_attribute

I'm currently working on a Ruby on Rails app with a very deep content model. There are many different "same-but-different" types of content to be managed. The "same" parts are roughly similar structure, like simple list items. The "different" parts are usually more meta-data oriented, such as different field labels.

I didn't want to end up with dozens of tables in the db for all these types. I also liked the idea of being able to easily search across them content types, so a relatively flat db structure would facilitate that.

My solution? Create a single table with some generic content holding fields something like the following:

RUBY:
  1. #migration
  2. class CreateListItems <ActiveRecord::Migration
  3.   def self.up
  4.     create_table :list_items do |t|
  5.       t.column :owner_id, :integer
  6.       t.column :type, :string
  7.       t.column :text, :text
  8.       t.column :text2, :text
  9.     end
  10.   end
  11.  
  12.   def self.down
  13.     drop_table :list_items
  14.   end
  15. end
  16.  
  17. # model
  18. class ListItem <ActiveRecord::Base
  19.   validates_presence_of :text 
  20. end

Now, for the various content types, use single-table inheritance to let all the models track back to the same table (the "type" field above is necessary for this to work). Also, to make the attributes match your content types, use an alias_attribute call to map the attribute names to the generic ones in the parent table. Such as:

RUBY:
  1. class Question <ListItem
  2.  
  3.   alias_attribute :question, :text
  4.   alias_attribute :answer, :text2
  5.  
  6. end

Now you'll be able interact with the Question instances naturally (q.question=, q.answer=), and any other content types you derive from ListItem.

Monday, April 2nd, 2007 at 9:34 pm and is filed under Ruby on Rails. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

3 Responses to “Rails: flatten your content model with single-table inheritance and alias_attribute”

  1. Sean Schofield Says:
    April 7th, 2008 at 10:48 am

    Nice approach and I love the blog name. Still chuckling over that …

  2. Nathan Says:
    June 24th, 2008 at 10:27 pm

    Hi. First off, please let me apologise in advance - I’m not a fan of Ruby nor Rails, but I require it for my work

    I am currently having what I would consider to be a fairly fundamental problem with STI - namely what if I define “validates_presence_of” in the base class, when creating a subclass, all validation errors are doubled - with a single “.save” call. It is definitely pertaining to extending the base class, because if I set the subclass to handle the validation itself, then all works fine.

    This would seem to defeat the point of inheritance in this context - all that’s been spared is multiple-tables, the validation calls still needs to be duplicated between all the subclasses.

    For the life of me, I cannot find any other reference to this quirk, so it is a case of just nobody caring, or has nobody noticed this?

  3. greg Says:
    June 25th, 2008 at 9:09 am

    Guess I’m not sure what you mean about errors being “doubled”, could you post a specific example?

Leave a Reply