A different way to do polymorphic associations

I did not like the way that Rails did polymorphic associations. I
found it impossible to add constraints into the database itself to
make sure that things were hooked up like they were suppose to be.
And doing the validation of all the if's, and's, and but's in Rails
appeared to me would lead to very expensive validations.

I also did not like the concept behind single table inheritance. I
find that whole concept extremely lame.

Mostly from ideas I got from the Postgres mailing list, I implemented
another way to do polymorphic associations. It seems to be working
for me. I thought I would share it. There are definitely some rough
edges but those are not getting in my way right now. I've managed to
tip toe around and get this to work with no modifications to Rails and
only a small amount of work (once the tricks are figured out).

The polymophic base class in this example I call ItemBase (with a
table of item_bases). The migration looks like this:

class CreateItemBases < ActiveRecord::Migration
  def self.up
    create_table :item_bases, :id => false do |t|
      t.integer :item_id, :null => false
      t.string :item_type, :null => false
      t.timestamps
    end
    execute "ALTER TABLE item_bases ADD CONSTRAINT
fk_item_bases_item_type
             FOREIGN KEY (item_type) REFERENCES
item_types(class_name)"
    execute "CREATE OR REPLACE FUNCTION item_id_test(item_id INTEGER,
item_type TEXT)
                 RETURNS BOOLEAN AS $$
                 DECLARE
                     tn TEXT;
                     qry TEXT;

                 BEGIN
                     SELECT INTO tn table_name FROM item_types
                         WHERE class_name = item_type;
                     IF NOT FOUND THEN
                         RETURN FALSE;
                     END IF;
                     qry = 'SELECT item_id FROM ' || quote_ident(tn)

' AS tn ' ||

                           'WHERE tn.item_id = ' || item_id::text ||
';';
                     EXECUTE qry;
                     IF NOT FOUND THEN
                         RETURN FALSE;
                     END IF;
                     RETURN TRUE;
                 END;
             $$ LANGUAGE plpgsql;"
    execute "ALTER TABLE item_bases ADD CONSTRAINT
ck_item_bases_item_id
             CHECK (item_id_test(item_id, item_type))"
    execute "ALTER TABLE item_bases ADD CONSTRAINT key_item_id
             UNIQUE (item_id)"
    execute "ALTER TABLE item_bases ADD CONSTRAINT key_item_tuple
             UNIQUE (item_id, item_type)"
    execute "CREATE SEQUENCE item_bases_item_id_seq"
  end

  def self.down
    drop_table :item_bases
    execute "DROP SEQUENCE item_bases_item_id_seq"
    execute "DROP FUNCTION item_id_test(INTEGER, TEXT)"
  end
end

The model looks like this:

class ItemBase < ActiveRecord::Base
  set_primary_key "item_id"
  belongs_to :item, :polymorphic => true

  def id
    item_id
  end
end

In this example, the subclasses can be companies, people, etc. The
migration to create the companies table is:

class CreateCompanies < ActiveRecord::Migration
  MY_CLASS_NAME = "Company"
  MY_TABLE_NAME = "companies"

  def self.up
    create_table MY_TABLE_NAME, :id => false do |t|
      t.integer :item_id, :null => false
      t.string :item_type, :null => false, :default =>
MY_CLASS_NAME
      t.timestamps