Project Ramon

A learning journey from a Ruby noob perspective

Exploring Rails: Single Table Inheritance

Hello and happy Wednesday!

In the last post, we covered a solution towards using the Rails’ Form Helper accepts_nested_attributes_for to give us a convenient ability to create data fields for multiple models to save and retrieve. This is also known as creating a multi-part form.

At the time I hadn’t figured out how to implement Single Table Inheritance properly, and instead created 2 phone number classes to represent a primary and secondary number. After some quick looking around, I found some pretty insightful tutorials that allowed me to use STI in order to DRY out my two redundant classes from the last post.

What I did Wrong

Lets take a quick look at the code from my last post, in order to demonstrate the problem and set the stage for implementing STI properly in Rails.

I was having an issue with seeing the attribute fields commit or retrieve the data stored in them, so when I created an object, the attributes were all evaluating to nil. Finally, I realized that the has_many associations for primary_phones and secondary_phones were unnecessary. It’s unnecessary because I’m using inheritance.

Creating one clear interface for all of PhoneNumber‘s sub-classes means I have a lot less to pay attention to and I can fine tune as needed by adding or overriding instance methods if need be.

When to use STI

Before we cover the steps towards using STI, lets go over when STI can be considered as a viable option.

This blog post, covers it nicely:

STI should be considered when dealing with model classes that share much of the same functionality and data fields, but you as the developer may want more granular control over extending or adding to each class individually. Rather than duplicate the code over and over for multiple tables (and not being DRY) or forego the flexibility of adding idiosyncratic functionality or methods, STI permits you to use keep your data in a single table while writing specialized functionality.

This is exactly what we need to DRY out my redundant PrimaryPhoneNumber and SecondaryPhoneNumber classes in the example at the top of this post.

I also stumbled upon this post and wanted to include it as something to personally keep in mind.

3 Reasons Why You Shouldn’t use STI

Here’s is an excerpt from that post:

The only time STI is the right answer is when you have models with exactly the same data, but different behavior. You don’t compromise your data model, and everything stays neat and tidy. I have yet to see a case in the wild where this rule holds, though.

If you are using STI (or inheritance in general) to share code, you’re doing it wrong. Having many tables does not conflict with the Don’t-Repeat-Yourself principle. Ruby has modules, use them. (I once had a project where a 20 line hash drove the creation of migrations, models, data loaders and test blueprints.)

Implementing STI in Rails

So here is an outline of how I was able to correctly implement this pattern for my application.

  1. Create the base class
  2. Along with your needed attributes, add a :type attribute as a string to the base class
  3. Create any necessary descendant classes

Step1: This is where I’ve added the attributes that will be inherited by both of my child classes. Note that this base class inherits from ActiveRecord::Base.

Step2: Here all we need to do is add the attribute :type to our phone_numbers table in the database.

exploring_sti1_img1

Now to add the :type to Rails’ whitelist of attributes (note: I’m using Rails 3.2.x).

For Rails4.x we would create or add our :type attribute to the end of our permit arguments like it says here in the RailsAPI:

exploring_sti1_img5

And since the migration has been ran, we can confirm by taking a quick detour to look at our schema.rb file.

exploring_sti1_img2

Step3: Time to create our descendant class’. No need to add attributes, because they are going to be inherited from the base class PhoneNumber.

Now lets have a bit of fun and see how we can benefit from us implementing this pattern in our Rails application.

STI in Action!

exploring_sti1_img3

We can already see from the example above, that PrimaryPhone is properly inheriting the :area_code and :number attributes from it’s parent, PhoneNumber.

Here’s something pretty neat, we can call all phone numbers through our base class and then have our :type attribute tell us which type of number we have stored.

exploring_sti1_img4

So we can call PhoneNumber.all and receive a list of all numbers (including any base class objects) and then allow :type to ‘categorize’ which type of number object we’re looking at.

Learning Resources

I hope you’ve found this post on implementing STI in Rails informative. Here are a few resources that I found both insightful and easy to follow.

  1. STI Rails Tutorial by: Charles Max Wood
  2. STI Best Practices in Rails by: Emphasized Insantiy

Stay tuned…

Advertisements

Categories: Ruby, Ruby on rails

Tags: , ,

2 replies

  1. Reblogged this on bob-roberts.net and commented:
    As usual a great article by Ramon!!

  2. Thanks for this post, Ramon. I found it a useful review when I needed to apply STI in a project.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s