A plugin that adds multi-table inheritance support to Rails using Postgres inheritance. For more information on Postgres inheritance, see www.postgresql.org/docs/8.3/static/ddl-inherit.html.
Assuming you have a base table migration like this:
class CreatePetsTable < ActiveRecord::Migration def self.up create_table :pets, :inherits_from => :profiles do |t| t.string :name, :limit => 64 t.string :species, :limit => 64 t.timestamps end end end
You can create an inherited table using the :inherits_from option.
class CreateDogsTable < ActiveRecord::Migration def self.up create_table :dogs, :inherits_from => :pets do |t| t.string :breed, :limit => 64 end ## # Executes the following in postgres: # CREATE TABLE dogs ( # "breed" character varying(64) DEFAULT NULL NULL # ) INHERITS (profiles) end end
The inherited table has all the columns of the base table in addition to any fields added in the migration. You just need to add a model for the inherited table and use the multi_table_inheritance directive.
class Dog < Pet multi_table_inheritance end
You can find inherited models through the base class, and they will be of the inherited type, just like with single-table inheritance. However, by default, when you find inherited models through the base class, all attributes added in just the inherited table will be missing. Single-table inheritance does not have this problem because all attributes exist in all classes in the hierarchy.
Pet.find(11) => #<Dog:0x19840f8 @attributes={"id"=>11, "name"=>"Daisy", "species"=>"Dog"} Dog.find(11) => #<Dog:0x1938284 @attributes={"id"=>11, "name"=>"Daisy", "species"=>"Dog", "breed"=>"Pit/Lab Mix"}
If you would like inherited attributes to be added the inherited models when finding from the base class, use the :add_fields option.
class Dog < Pet multi_table_inheritance :add_fields => true end Pet.find(11) => #<Dog:0x1938284 @attributes={"id"=>11, "name"=>"Daisy", "species"=>"Dog", "breed"=>"Pit/Lab Mix"}
This may have performance implications for you, because it fetches the record again from the inherited table. However, if you are using a model caching system (e.g. github.com/ninjudd/record_cache), the impact should be minimal.
sudo gem install ninjudd-multi_table_inheritance -s http://gems.github.com
Requires Rails 2.3 because multi_table_inheritance overrides the default_select method in ActiveRecord::Base. Or alternatively, you can apply the following patch to construct_finder_sql in activerecord/lib/active_record/base.rb:
+ def default_select(qualified) + if qualified + quoted_table_name + '.*' + else + '*' + end + end + def construct_finder_sql(options) scope = scope(:find) - sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} " + sql = "SELECT #{options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} " sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
Copyright © 2009 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE