Notebook

April 03, 2008 1:53PM

Building a CMS: Simplifying Posts with Single Table Inheritance

"Posts" will make up the majority of my site's content, and there will be a few different types: articles, reviews, links, and comments. While I could create separate tables in the database for each, I've decided to utilize Rails' single table inheritance, whereby multiple models share the same table and some common behavior. However, STI is not limited to Rails; it's a general design pattern where one table is used for multiple objects or models.

Rails and Single Table Inheritance

In Rails, every table in the database is represented as a "Model" (which follows the model-view-controller design). So, for instance, a standard Post might look something like this:

class Post < ActiveRecord::Base
  # model methods go here
end

This model will store its data in the "posts" table in your database. Now, to implement STI in Rails, all I have to do is create models, but instead of inheriting from ActiveRecord::Base, I inherit from Post, like below:

class ArticlePost < Post
  # model methods go here
end

Now all that's left is to add a "type" column to the "posts" table in the database, and Rails automatically figures out the rest. I'll go into more detail about this in a future post.

Why STI is Awesome

The basic reason I wanted to go with STI is it makes it very easy to pull different types of data from the database at once and display them. Instead of making a query for each type of post, I can just do @posts = Post.find(:all), and Rails pulls every type of Post and even makes each the right object type (e.g. if the table row has a type of "ArticlePost," Rails returns an ArticlePost object, not just a Post object).

Single Table Inheritance also makes it very easy to share behaviors between different types of posts, especially the way it's implemented in Rails. Since each object is a child of the Post model, I only have to write standard behavior once, such as post status and commenting.

Potential Pitfalls

One of the main problems with STI is that it can lead to cumbersome database tables with many columns, since each child model might require different fields. When the database table gets very large, this could potentially cause issues and slowdowns. However, in my case, since each post has the same basic fields (title, body, author, etc.) with only a few specific fields (product name for reviews, link urls for link posts, etc.), I don't see this becoming an issue. Also, since I'm never expecting the database table to reach, say, 100,000 rows, it's doubtful there will be much of a performance loss.

Comments as Posts?

While it was a simple decision to handle articles, reviews, and links as subclasses of "Post," I had a little trouble coming up with how to best handle comments. I had two choices, either I make comments just another type of Post (i.e. CommentPost), or I create a new table and model just for comments. In the end decided on STI, because, once again, I can take advantage of shared behaviors to cut down on code. Also, since a comment is just a "Post," it will make it easy to "comment on a comment" to create a threaded discussion.

More to come

Since this was more of an overview of STI, in a future post, I'll try to explore more of Rails' implementation of single table inheritance and how to best use it.

Did you like this entry? Make sure to subscribe to my RSS feed to keep up-to-date with my newest entries and links.

Comments

Avatar

Colin Devroe

April 03, 2008 at 3:27PM #

I think this is an interesting thing to keep track of for sure. The "old school" DBA in me wants to recommend that you leave comments, trackbacks, linkbacks, and hrefbacks in their own table because they will become 4 or 5 times the size of your normal posts. Meaning that, on average, you can expect more than one comment on each post.

Lookups could begin to get cumbersome if you decide to allow global searching.

Avatar

Kyle

April 03, 2008 at 4:16PM #

The size of the table definitely was something that concerned me. However, since it will be a relatively small scale site, I don't think it should be an issue. Also, I'm going to be heavily caching everything so as to eliminate lengthy queries.

If comments do start to become a problem, it should be easy enough to separate them into their table to keep things speedy.

Leave a Comment

(required)

(required, never displayed)

(optional)

Ajax-loader