# STI versus Composition...or the headaches of one big table

**URL:** <https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664>\
**Category:** Rails\
**Created:** [June 17, 2006, 5:47am UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664 "2006-06-17T05:47:59Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![BA\_Baracus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e5b9ba/32.png) [@BA\_Baracus](https://www.ruby-forum.com/u/BA_Baracus)\
**Post date:** [June 17, 2006, 5:47am UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664/1 "2006-06-17T05:47:59Z")

</div>

Guys,

I have a relationship between model classes that I believe is best  
represented by inheritance, but the likelihood that things will change  
often is driving us to composition instead.

So, I have a class called Autos, and subclasses called Suvs, Minis,  
Mids, Sports, for example.

We have been requested to avoid the STI approach to this, because of  
fear of a quickly growing table with many empty fields, and the fear of  
having to add or delete properties of one of the above categories and  
having to process every row in the entire table.

I’m trying to get my head around the best way to do this. I’d like to  
break it out via composition, but having a Autos table with an suv\_id,  
mini\_id, mid\_id, and sports\_id (for all possible combos) seems like  
really bad design.

I suppose I could have the Autos table have a sub\_type\_id and sub\_type  
column, and somehow use this to map. However, I’m unsure how to go about  
this…composed\_of doesn’t seem to be designed with this situation in  
mind.

Any insight or suggestions you may provide will be very welcome.

## Thanks! B.A.

B.A. Baracus: I thought you weren’t crazy no more?  
Murdock: Only on paper.

---

<div class="post-metadata">

**Author:** ![BA\_Baracus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e5b9ba/32.png) [@BA\_Baracus](https://www.ruby-forum.com/u/BA_Baracus)\
**Post date:** [June 17, 2006, 6:03am UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664/2 "2006-06-17T06:03:20Z")

</div>

Hi !

17 Jun 2006 03:45:22 -0000, BA Baracus  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> I suppose I could have the Autos table have a sub\_type\_id and sub\_type  
> column, and somehow use this to map. However, I’m unsure how to go about  
> this…composed\_of doesn’t seem to be designed with this situation in mind.

If you used this approach, you would be using polymorphic associations:

class CreateAuto \< AR::Migration  
def self.up  
create\_table :autos do |t|  
t.column :subclass\_id, :integer  
t.column :subclass\_type, :string  
end  
end  
end

class Auto \< AR::Base  
belongs\_to :subclass, :polymorphic =\> true  
end

Then, autos.subclass\_id + autos.subclass\_type identify the table/PK of  
the relationship. See  
[http://wiki.rubyonrails.com/rails/pages/UnderstandingPolymorphicAssociations](http://wiki.rubyonrails.com/rails/pages/UnderstandingPolymorphicAssociations)  
for some documentation.

Hope that helps !

---

<div class="post-metadata">

**Author:** ![BA\_Baracus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e5b9ba/32.png) [@BA\_Baracus](https://www.ruby-forum.com/u/BA_Baracus)\
**Post date:** [June 17, 2006, 8:56am UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664/3 "2006-06-17T08:56:45Z")

</div>

17 Jun 2006 05:53:50 -0000, BA Baracus  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Perfect…thanks! Had no idea Rails supported this! Is this a 1.1 feature?

Yes.

Bye !

---

<div class="post-metadata">

**Author:** ![BA\_Baracus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e5b9ba/32.png) [@BA\_Baracus](https://www.ruby-forum.com/u/BA_Baracus)\
**Post date:** [June 17, 2006, 7:56am UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664/4 "2006-06-17T07:56:02Z")

</div>

On Saturday, June 17, 2006, at 12:00 AM, Francois B. wrote:

> Hi !
> 
> 17 Jun 2006 03:45:22 -0000, BA Baracus [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > I suppose I could have the Autos table have a sub\_type\_id and sub\_type  
> > column, and somehow use this to map. However, I’m unsure how to go about  
> > this…composed\_of doesn’t seem to be designed with this situation  
> > in mind.
> 
> If you used this approach, you would be using polymorphic associations:

Perfect…thanks! Had no idea Rails supported this! Is this a 1.1  
feature?

---

<div class="post-metadata">

**Author:** ![BA\_Baracus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e5b9ba/32.png) [@BA\_Baracus](https://www.ruby-forum.com/u/BA_Baracus)\
**Post date:** [June 17, 2006, 2:31pm UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664/5 "2006-06-17T14:31:09Z")

</div>

On Saturday, June 17, 2006, at 3:45 AM, BA Baracus wrote:

> fear of a quickly growing table with many empty fields, and the fear of  
> this…composed\_of doesn’t seem to be designed with this situation in mind.
> 
> * * *
> 
> Rails mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.rubyonrails.org/mailman/listinfo/rails](http://lists.rubyonrails.org/mailman/listinfo/rails)

I wouldn’t write off the STI approach. Updating the table with a  
migration is pretty painless and can also be used to populate the  
relevant fields. I don’t think there will really be that much of a  
performance problem.

This sounds a bit like premature optimization to me. If you are really  
concerned about it, set up a test environment to simulate stress  
conditions and do some benchmarking before you try to fit a square peg  
into a round hole.

\_Kevin

---

<div class="post-metadata">

**Author:** ![BA\_Baracus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e5b9ba/32.png) [@BA\_Baracus](https://www.ruby-forum.com/u/BA_Baracus)\
**Post date:** [June 18, 2006, 12:43am UTC](https://www.ruby-forum.com/t/sti-versus-composition-or-the-headaches-of-one-big-table/63664/6 "2006-06-18T00:43:45Z")

</div>

On Sat, Jun 17, 2006 at 03:45:22AM -0000, BA Baracus wrote:  
[…]  
} We have been requested to avoid the STI approach to this, because of  
} fear of a quickly growing table with many empty fields, and the fear  
of  
} having to add or delete properties of one of the above categories and  
} having to process every row in the entire table.  
[…]  
} Any insight or suggestions you may provide will be very welcome.

If your problem fits the following criteria, read on:

1. The subclass-specific fields are information about the object itself  
and  
has no relationship to other objects.

2. The subclass-specific fields will not need to be queried (i.e.  
filtered,  
grouped, or aggregated), just read and written.

3. The table in question will never need to be accessed by a non-Rails  
application.

If all those criteria apply, you can use a serialized column. The column  
should be declared text in the database, and the model should look  
something like this (assuming the column is named serial\_col and the  
table  
is Foos):

class Foo \< ActiveRecord::Base  
serialize :serial\_col

def self.serial\_field(\*fields)  
fields.each { |field|  
field = field.to\_sym  
define\_method(field) { serial\_col[field] }  
define\_method("#{field}=") { |val| serial\_col[field] = val }  
#define\_method("#{field}?") #fill in as desired  
}  
end

def serial\_col  
self[:serial\_col] ||= {}  
end  
end

In your subclasses you would created pseudo-fields:

class Bar \< Foo  
serial\_field :baz  
end

} Thanks!  
} B.A.  
–Greg
