Any good alternative to single-table-inheritance?

I’m looking to implement model inheritance in a new application. Is
there any good alternative to single-table-inheritance?

On 7/21/06, Alder G. [email protected] wrote:

I’m looking to implement model inheritance in a new application. Is
there any good alternative to single-table-inheritance?


-Alder


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

There was a new plugin released recently. I havn’t had a good look at
it
but it certainly is an alternative

http://www.agilewebdevelopment.com/plugins/inherits_from

On Thursday, July 20, 2006, at 5:06 PM, Alder G. wrote:

I’m looking to implement model inheritance in a new application. Is
there any good alternative to single-table-inheritance?


-Alder


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

Why do you want an alternative?

_Kevin
www.sciwerks.com

Kevin O. wrote:

Why do you want an alternative?

_Kevin
www.sciwerks.com

Mmmm I do. I’ll explain why. As RoR learning project I decided to try
reproducing the core funcionality of an internal CMS-like tool at my
org. The database already followed most rails-friendly conversions, so
starting was a breeze. But here’s the problem:
I have in there “resources”, which can be links, various documents and
archives, quizzes, forums and on and on for almost 20 types of resource.
There is a resources table which holds the common columns for all
resources, then one table for each resource type, and some have in
excess of 20 columns specific for that type of resource.
If I have to mashup those into a single STI table i’ll end up with a
table having between 300 and 400 columns, which I think everyone would
agree it’s a bad thing.

The alternative? Resource have a belongs_to polymorphic relation to all
20 different resource models, which each have a has_one dependent
relationship back to the Resource model. This allows me to keep separate
tables, and somehow keep everything working. The problem? My code isn’t
making use of inheritance, as I can’t say:
class Link < Resource

and have to keep using my aggregation cludge and doing ugly stuff like:

link.resource.name

And I have to always remember deleting links and not resources, as the
dependence for deleting goes only one way.

Real support for some kind of class table inheritance would make all
this moot, but I’ve been looking into ActiveRecord and can’t see it
working as a simple plugin. Adding the functionality would stomp out all
the simplicity from most of the current code. Doing away with the Just
One Table per Model principle isn’t the ActiveRecord way.

So I’m just stuck with my project, as I have to choose between an
inacceptably ugly database or non-OO ugly code, and I chose Rails to
flee all the uglyness that was there before.

On 20 Jul 2006 15:57:47 -0000, Kevin O.
[email protected] wrote:

http://lists.rubyonrails.org/mailman/listinfo/rails

Why do you want an alternative?

I have a parent model class Foo, and two subclasses Bar and Baz.

The thing is that Bar and Baz are very different. They share 4
attributes from Foo and an additional common attribute among
themselves, but also each have 6-7 attributes that are non-shared.

So if I implement this inheritance model with STI, I end up with a
pretty large table (~20 columns), of which each model uses not more
than half (and Foo instances use only a fifth).

This looks very non-optimal, and is likely to get worse down the road,
since Foo is expecting several additional children, each of whom would
add about 6+ more non-shared attributes. I’d soon end up with a 50+
column table for producing pretty simple (10 attribute) model
instances. Much unnecessary complexity.

Looks like the plugin linked by Daniel would prevent that, I’d have a
look at is (thanks Daniel!)

Juan Felipe G. wrote:

The alternative? Resource have a belongs_to polymorphic relation to all
20 different resource models, which each have a has_one dependent
relationship back to the Resource model. This allows me to keep separate
tables, and somehow keep everything working. The problem? My code isn’t
making use of inheritance, as I can’t say:
class Link < Resource

and have to keep using my aggregation cludge and doing ugly stuff like:

link.resource.name

And I have to always remember deleting links and not resources, as the
dependence for deleting goes only one way.

Real support for some kind of class table inheritance would make all
this moot, but I’ve been looking into ActiveRecord and can’t see it
working as a simple plugin. Adding the functionality would stomp out all
the simplicity from most of the current code. Doing away with the Just
One Table per Model principle isn’t the ActiveRecord way.

So I’m just stuck with my project, as I have to choose between an
inacceptably ugly database or non-OO ugly code, and I chose Rails to
flee all the uglyness that was there before.

Yes, I agree with your sentiments. But Ruby has enough mojo to make the
pain bearable. You can create a mixin module to share behavior in your
models, and you can use delegation or a method_missing hack to make the
explicit message forwarding go away. The polymorphic belongs_to
assocations are still kinda ugly, but at least your code doesn’t have to
be ugly.


Josh S.
http://blog.hasmanythrough.com

So as it seems to be the current best alternative, I’ll post some of my
model stuff as a hint:

#The “parent” model for all resources, resources are listed in sections
#the database table needs “instance_id” and “instance_type” columns
class Resource < ActiveRecord::Base
belongs_to :section
belongs_to :instance, :polymorphic => :true
end

#A Link is one type of resource, so every link is the

“instance” of a resource

class Link < ActiveRecord::Base
include ResProperties
has_one :resource, :as => :instance, :dependent => :destroy
end

#A Lesson is one type of resource, so every lesson is the

“instance” of a resource

class Lesson < ActiveRecord::Base
include ResProperties
has_one :resource, :as => :instance, :dependent => :destroy
end

… and on and on for 18 more children models

#In this module I put stuff every “child” should have inherited,
#for example, every resource of any type has a name, which lives in the
#resources table
module ResProperties
def name
resource.name
end
end

Beware the possibility of orphan children. Deleting a link or lesson or
whatever will take care automagically of the corresponding resource.
Deleting a resource will leave the corresponding “instance” there
forever.

I guess some ruby magic in the ResProperties module would go a long way,
as Josh suggested, I have to read deeper into my new and fresh pickaxe
copy.

BTW…I’m quite happy about having the has_many :though guru agreeing
with my sentiments about such matters, does wonders for my newbie pride
:wink:

On 7/20/06, Juan Felipe G. [email protected] wrote:

I have in there “resources”, which can be links, various documents and
archives, quizzes, forums and on and on for almost 20 types of resource.
There is a resources table which holds the common columns for all
resources, then one table for each resource type, and some have in
excess of 20 columns specific for that type of resource.
If I have to mashup those into a single STI table i’ll end up with a
table having between 300 and 400 columns, which I think everyone would
agree it’s a bad thing.

Yup, my reason for looking for an alternative is pretty much the same.

The alternative? Resource have a belongs_to polymorphic relation to all
20 different resource models, which each have a has_one dependent
relationship back to the Resource model. This allows me to keep separate
tables, and somehow keep everything working. The problem? My code isn’t
making use of inheritance, as I can’t say:
class Link < Resource

and have to keep using my aggregation cludge and doing ugly stuff like:

link.resource.name

As Josh already hinted, you can easily (e.g. through #method_missing)
have unanswered methond calls on link routed to link.resource.

You can also meta-programmatically generate the boiler-plate code for
the 18 children models you mentioned. I would so do that if I were
you.

Ultimately, as far as the code layer is concerned, Josh is right:
Ruby’s meta-programming can make the pain go away.

However, as I invariably end up at some point or other dealing
directly with the database on all long-running project, I’d hesitate
to create 50+ tables which aren’t essentially necessary for ~10
attribute models.

Also, when tables might reach 400+ columns such as in your case (and
in the long run definitely possible on mine), I’d start worrying about
stuff like performance (e.g. select * would have to return 400 columns
per record… brrr) and even (gasp) space. Depending on the
databasse, 400 columns might really hurt when you’re doing a million
inserts a day.

If I was 20 yrs. old punk once again I would have already wrote
something like:

class HyperActiveRecord < ActiveRecord::Base

And go on overriding the columns, attributes, find, update, insert,…
methods with the sql join mojo necessary to have proper model
inheritance… But I’m too old and lazy by now. Instead my project is
stopped while I ponder about easier options.

Anyone trying, feel free to pick up my class name, I like it a lot :slight_smile:

On 7/20/06, Juan Felipe G. [email protected] wrote:

#A Link is one type of resource, so every link is the
has_one :resource, :as => :instance, :dependent => :destroy
resource.name
end
end

That’s the method recommended by DHH on AWDWR. Except he suggests to
call the pseudo-baseclass something like ResourceMetadata.

It’s in the section about Single Table Inheritance, I was just
wondering whether a new “best practice” sprung up more recently, since
frankly this one isn’t perfect.

The are a few solutions if you do a google ‘rails single table
inheritance’ but none are 100%, for example some functionality is lost
such as associated join along the chain of inheritance or they are db
specific such as Postgres table inheritance.

I started by using polymorphic joins to a common model but the code is
kinda odd, it would be great if the Rails core had STI implemented…
Does anyone know of any progress in this area?

On 7/20/06, Juan Felipe G. [email protected] wrote:

If I was 20 yrs. old punk once again I would have already wrote
something like:

class HyperActiveRecord < ActiveRecord::Base

And go on overriding the columns, attributes, find, update, insert,…
methods with the sql join mojo necessary to have proper model
inheritance… But I’m too old and lazy by now. Instead my project is
stopped while I ponder about easier options.

Don’t brood over this too much; either go with the AWDWR best practice
(the minor problems you saw in it are solveable, and you end up with
something that’s not really kludgy in any way) or have a look at the
plugin.

Either way, in several months you’ll be such a Rails whiz you’d be
able to switch MOs in less time than you’ll take “pondering your
options” right now :wink: