Single-Table Inheritance with Tests in Ruby on Rails

Single-table inheritance was a difficult concept for me to grasp when I first started using Ruby on Rails. Part of this might stem from the fact that it’s not a perfectly modeled concept in Rails itself. Relational databases like MySQL, PostgreSQL, and sqlite don’t have any concept of (inherited) sub-tables.

Let’s say you want to track pets. Cats and dogs need to be treated differently, but they basically have the same set of attributes, and share some methods as well. Here’s how we setup our models:

# app/models/pet.rb
class Pet < ActiveRecord::Base
  validates_attributes :name

  def speak
# app/models/dog.rb
class Dog < Pet
  def speak
# app/models/cat.rb
class Cat < Pet
  def speak

Notice we include a default speak method in the parent class. This isn’t required, but it will help with any other pet types we may create in the future. This will be the default, so if we add a Fish category, we don’t need to define its own speak method separately.

All three models will share a common database table. In our migration, we’ll need to add a string column called “type”, that will contain the class name of the individual record:

class CreatePets < ActiveRecord::Migration
  def self.up
    create_table :pets do |t|
      t.string :name
      t.string :type


  def self.down
    drop_table :pets

This is how Rails will know which records are cats, and which are dogs. You’ll usually never have to work with this column directly. Now calls to Dog.all will return only dog records from the pets table. Calling speak on a pet record will return “Woof!” for a dog record, and “Meow!” for a cat record.

Now, how do we test this? We should create a test file for each model class. We’ll test everything in that is included in the parent model in its test file, then only test the things that change in the child model tests:

# test/unit/pet_test.rb
require 'test_helper'

class PetTest < ActiveSupport::TestCase
  def test_should_validate_presence_of_name
    pet =
    assert !pet.valid?
    assert pet.errors.on(:name).include?("can't be blank")

  def test_should_speak_blank
    pet =
    assert_equal '', pet.speak
class DogTest < ActiveSupport::TestCase
  def test_should_bark
    dog =
    assert_equal 'Woof!', dog.speak
class CatTest < ActiveSupport::TestCase
  def test_should_meow
    cat =
    assert_equal 'Meow!', cat.speak

Single-table inheritance is powerful, and only slightly tricky to grasp. It’s well worth learning.


Tags: , , , ,

2 Responses to “Single-Table Inheritance with Tests in Ruby on Rails”

  1. Rafael Says:


    can you help me about single table inheritance testing using rspec?

  2. Ereditarieta` in Ruby on Rails | Says:

    […] […]

Leave a Reply

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

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

Google+ photo

You are commenting using your Google+ 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 )


Connecting to %s

%d bloggers like this: