# A different way to do polymorphic associations

**URL:** <https://www.ruby-forum.com/t/a-different-way-to-do-polymorphic-associations/112049>\
**Category:** Rails\
**Created:** [August 14, 2007, 6:05pm UTC](https://www.ruby-forum.com/t/a-different-way-to-do-polymorphic-associations/112049 "2007-08-14T18:05:02Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![pedz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/839c29/32.png) [@pedz](https://www.ruby-forum.com/u/pedz)\
**Post date:** [August 14, 2007, 6:05pm UTC](https://www.ruby-forum.com/t/a-different-way-to-do-polymorphic-associations/112049/1 "2007-08-14T18:05:02Z")

</div>

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  
#  
# Attributes start here  
#  
t.string :name, :null =\> false  
end  
execute “ALTER TABLE #{MY\_TABLE\_NAME} ALTER COLUMN item\_id  
SET DEFAULT nextval(‘item\_bases\_item\_id\_seq’)”  
execute “ALTER TABLE #{MY\_TABLE\_NAME} ADD CONSTRAINT  
#{MY\_TABLE\_NAME}_item\_type  
CHECK (item\_type = ‘#{MY\_CLASS\_NAME}’)"  
execute "ALTER TABLE #{MY\_TABLE\_NAME} ADD CONSTRAINT  
fk_#{MY\_TABLE\_NAME}\_item\_id  
FOREIGN KEY (item\_id, item\_type)  
REFERENCES item\_bases(item\_id, item\_type)  
ON DELETE CASCADE INITIALLY DEFERRED”  
ItemType.create(:table\_name =\> MY\_TABLE\_NAME, :class\_name =\>  
MY\_CLASS\_NAME)  
end

def self.down  
drop\_table MY\_TABLE\_NAME  
ItemType.destroy\_all(:table\_name =\> MY\_TABLE\_NAME)  
end  
end

I have not written a generator yet but instead I create a couple of  
constants and then the rest of the migration is the same except for  
the subclass specific fields.

The model is:

class Company \< ActiveRecord::Base  
set\_primary\_key “item\_id”  
set\_sequence\_name “item\_bases\_item\_id\_seq”  
has\_one :item\_base, :as =\> :item

# subclass specific validations

validates\_presence\_of :name  
end

First, as you can see, most of the migration is introducing  
constraints into the database. These are PostgreSQL specific. For  
other databases, there are probably similar concepts. And for those  
who do not believe in db constraints, just don’t do them.

In the constraints, another table is referenced: item\_types. Its  
associted class is ItemTypes. It simply maps table names to class  
names for the db to use. As part of the migration for each subclass,  
I add in the needed row into the item\_types table.

In brief, for item\_bases, the id is constrainted to be unique. I also  
constrain the ( id, type) tuple so I can use it as a foreign key. The  
item\_id\_test verifies that an entry id and type are in the proper  
table. Going the other direction, the companies table has a deferred  
constraint that a matching entry is in item\_bases. At the time of the  
commit, both entries must be there. There is no way for duplicates or  
other weird mixtures. These same constraints could be lifted up into  
Rails if that is the user’s choice.

The main difference between this style and the normal Rails style of  
polymophic association is that the id and type are in both the base  
and the subclass. The base does not have its own id. So, with an id,  
you can find the base instance. From the base instance, you can find  
the subclass instance. Also, from the subclass instance, you can find  
the base instance. This is roughly the same as normal Rails – the  
only difference is the id is the same for both the base instance and  
the subclass instance. (The type is the same too.)

I find this works well for me. It is robust and somewhat fool proof  
once it is set up. There is nothing here that could not be  
generalized so a generator could be written to create the base class  
and a second generator that would create each subclass passing in the  
name of the base class.

Someone has mentioned that this can not be extended. i.e. the base  
class could not itself be a subclass of another class. But I don’t  
understand why not. I have not tried it so I can’t say for sure.  
But, the subclass specific attributes could be foo\_id and foo\_type  
which would form the base of the foo class.

The one rough edge is there is no wrapper around the whole thing that  
will return an Item. I don’t know enough yet about the magic of Rails  
and ActiveRecord to do this. It seems like it could be done somehow.

If anyone finds this useful, let me know. I’d like to hear what  
others think about it.

Thank you,  
Perry

---

<div class="post-metadata">

**Author:** ![pedz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/839c29/32.png) [@pedz](https://www.ruby-forum.com/u/pedz)\
**Post date:** [October 21, 2007, 7:35pm UTC](https://www.ruby-forum.com/t/a-different-way-to-do-polymorphic-associations/112049/2 "2007-10-21T19:35:51Z")

</div>

I think I may need to go this route. However first I need to exhaust  
the simpler options.

I’m still very new to ROR and it has been decades since I’ve done any  
serious programming.  
I like to think my design skills are up to date.

I would like to subclass a class in the model, and have its  
persistance handled for me (but I guess  
it isn’t so the first thing I need to do is find a pattern that works  
in most cases)

In my case I would like to say

A \< Active record

B \< A

and when I did a list (just a plain scaffolding list) of As I would  
get all the As and all the Bs listing only A columns

when I do a list of Bs I should get Bs only, with their columns from A  
and B.

Seems like this should be the default behavior, but I’m even having  
trouble finding it anywhere.  
None of the examples in the books I’m reading have inheritance in the  
domain model.

Thanks

On Aug 14, 10:05 am, Perry S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![pedz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/839c29/32.png) [@pedz](https://www.ruby-forum.com/u/pedz)\
**Post date:** [October 21, 2007, 9:30pm UTC](https://www.ruby-forum.com/t/a-different-way-to-do-polymorphic-associations/112049/3 "2007-10-21T21:30:34Z")

</div>

mkumba wrote:

> I think I may need to go this route. However first I need to exhaust  
> the simpler options.
> 
> I’m still very new to ROR and it has been decades since I’ve done any  
> serious programming.  
> I like to think my design skills are up to date.
> 
> I would like to subclass a class in the model, and have its  
> persistance handled for me (but I guess  
> it isn’t so the first thing I need to do is find a pattern that works  
> in most cases)
> 
> In my case I would like to say
> 
> A \< Active record
> 
> B \< A
> 
> and when I did a list (just a plain scaffolding list) of As I would  
> get all the As and all the Bs listing only A columns
> 
> when I do a list of Bs I should get Bs only, with their columns from A  
> and B.

So far, it sounds like you want just “Single Table Inheritance” which  
rails does out of the box.

[http://wiki.rubyonrails.org/rails/pages/SingleTableInheritance](http://wiki.rubyonrails.org/rails/pages/SingleTableInheritance)
