<?xml version="1.0" encoding="UTF-8"?>
<post>
  <author>Phil McClure</author>
  <body>What is it?
-----------

With single table inheritance you have a base model which inherits from ActiveRecord::Base, then one or more sub-classes, which inherit from the base model.

Single table inheritance is a software pattern described by Martin Fowler.  Since (most) databases don't support inheritance, there is an issue when trying to map objects to database tables.  This is known as the Object-relational impedance mismatch.

Rails uses the Single Table Inheritance pattern to solve this problem.  The basic idea is that another field in the base database table is used to store the type of the object.

Why use it?
-----------

If you want to acurately model a domain then inheritance is going to be necessary at some point or another.  So single table inheritance gives you this flexibility.

Be Careful!
-----------

Just be careful when using single table inheritance.  Since all the data from all the sub-types is include in one table, you can end up with a lot of "null"s scattered throughout the table.  These ultimately increase the size of the table and you could end up with a scaling problem on your hands. 

For instance, say you have an abstract object called "Employee" and several sub-classes called "FullTimeEmployee", "TempEmployee" and "StudentEmployee".  This is shown in the class diagram below:

Employee Hierarchy
------------------

As you can see, the super-class (Employee) has two instance variables "Name" and "Salary".  Further to this, each of the sub-types have an instance variable relating, specifically to them.  These instance variables in the sub-classes are what cause the problems.  If you have a look at the table below, all will become clear:

Type 	Name 	Salary 	Hours 	Duration 	University
FullTimeEmployee 	Jim 	10,000 	37 	null 	null
TempEmployee 	John 	15,000 	null 	5 	null
StudentEmployee 	Joe 	20,000 	null 	null 	Queens University, Belfast

As you can see, each type has nulls in the fields which don't apply to it.  This problem is only compounded when extra objects are added.  So, as I already mentioned, the scaling problems can be serious, so keep this in mind when modeling your application.

Coding it
---------

Using the "Employee" model above we first need to generate the Employee model:

    ruby script/generate model employee name:string salary:string 
    hours:string duration:string university:string type:string

Notice we have included a "type" field.  This is used to store the type of object that the record applies to.  Now migrate this into the database:

    rake db:migrate

Now, in the app/models folder create a model file for each sub-class:

    full_time_employee.rb

&lt;script src="http://gist.github.com/200186.js"&gt;&lt;/script&gt;

We can now test this out using the console:

    &gt;&gt; FullTimeEmployee.create!(:name =&gt; "Jim", :salary =&gt; "10,000", :hours =&gt; "37")
    &gt;&gt; TempEmployee.create!(:name =&gt; "John", :salary =&gt; "15,000", :duration =&gt; "5")
    &gt;&gt; StudentEmployee.create!(:name =&gt; "Joe", :salary =&gt; "20,000", 
       :university =&gt; "Queens University, Belfast")

Now, print the records, we just created, to screen:

    &gt;&gt; y Employee.all

!ruby/object:FullTimeEmployee
  attributes:
    name: Jim
    updated_at: 2009-06-12 19:16:42
    university:
    salary: "10,000"
    type: FullTimeEmployee
    id: "1"
    hours: "37"
    duration:
    created_at: 2009-06-12 19:16:42
  attributes_cache: {}

!ruby/object:TempEmployee
  attributes:
    name: John
    updated_at: 2009-06-12 19:19:50
    university:
    salary: "15,000"
    type: TempEmployee
    id: "2"
    hours:
    duration: "5"
    created_at: 2009-06-12 19:19:50
  attributes_cache: {}

!ruby/object:StudentEmployee
  attributes:
    name: Joe
    updated_at: 2009-06-12 19:19:59
    university: Queens University, Belfast
    salary: "20,000"
    type: StudentEmployee
    id: "3"
    hours:
    duration:
    created_at: 2009-06-12 19:19:59
  attributes_cache: {}

See how the type field has been updated for you?

Now, when we retrieve the employees, we want them to be of the appropriate type.  Let's see if this works by getting all employees and calling the "class" method for each.

    &gt;&gt; employees = Employee.all

    &gt;&gt; employees.each do |employee|
    ?&gt;    puts employee.class
    &gt;&gt; end

Outputs:
    FullTimeEmployee
    TempEmployee
    StudentEmployee

So it works!  Yah!

Summary
-------

Single table inheritance is extremely useful for modeling more complex domains.  However, it should be used with caution as it can lead to scaling problems.</body>
  <created-at type="datetime">2009-10-02T22:14:21Z</created-at>
  <id type="integer">18</id>
  <prev-body nil="true"></prev-body>
  <prev-graphic nil="true"></prev-graphic>
  <preview-body nil="true"></preview-body>
  <title>Single Table Inheritance with Rails</title>
  <updated-at type="datetime">2009-10-15T12:48:05Z</updated-at>
</post>
