Single Table Inheritance in Rails

Skip Baney

Handwire

The Setup

Traditional: Migration I


create_table :posts do |t|
  t.column :title,            :string
  t.column :body,             :text
  t.column :created_by,       :int
  t.column :updated_by,       :int
end

create_table :events do |t|
  t.column :title,            :string
  t.column :body,             :text
  t.column :location,         :text
  t.column :created_by,       :int
  t.column :updated_by,       :int
end

Traditional: Migration II


create_table :post_comments do |t|
  t.column :post_id,       :int
end

create_table :event_comments do |t|
  t.column :event_id,       :int
end

create_table :attendees do |t|
  t.column :event_id,       :int
end

Traditional: Models


class Post < ActiveRecord::Base
  acts_as_taggable
  has_many   :comments, :class_name => 'PostComment'
  belongs_to :creator
  belongs_to :updater
end

class Event < Content
  acts_as_taggable
  has_many   :comments, :class_name => 'EventComment'
  has_many   :attendees
  belongs_to :creator
  belongs_to :updater
end

Code Reuse is Sweet!

ORM and Inheritance

Concrete Table Inheritance

Class Table Inheritance

Single Table Inheritance

Rails uses STI

Don't like type?


class Blood < ActiveRecord::Base
  has_many :donors

  def inheritance_column
    'class_name'
  end
end

STI:

SIT: Migration


create_table :contents do |t|
  t.column :type,             :string
  t.column :title,            :string
  t.column :body,             :text
  t.column :location,         :text
  t.column :created_by,       :int
  t.column :updated_by,       :int
end

create_table :comments do |t|
  t.column :content_id,       :int
end

create_table :attendees do |t|
  t.column :content_id,       :int
end

STI: Models


class Content < ActiveRecord::Base
  acts_as_taggable
  has_many   :comments
  belongs_to :creator
  belongs_to :updater
end

class Post < Content
end

class Event < Content
  has_many :attendees
end

Pros

Cons

Best Practice?

Alternatives

Thanks!