Table inheritance in Rails. Right way

Hi all!

I want a simple way to do a “table inheritance” in my DB.

For example I have a table “contents” with general attributes for all
content types. Something like this:

id
creator_id
created_at
modifier_id
modified_at
… and so on …

This table describes abstract content object, I’ll never want to create
it.
Then I make article_contents table:

id
title
body
content_id <- possible we need foreign key (?)

Now, I want an easy way to work with my model ArticleContent to do CRUD
operations on it. ArticleContent model must store their attributes in 2
tables: article_contents and contents, but for my business logic level
this difference should be clear(as if all attributes are stored in
article_content table), and must work well on all database backends.

Short version: DRY principle. Don’t copy table attributes from contents
table to article_contents.

P.S. Sorry for my English.

Hi Vlad,

It sounds like you want class table inheritance, which there’s no out
of the box solution for yet (someone correct me if I’m wrong). I’ve
been dealing with this all week and found something that seems to
work in my tests.

I have similar table setups, one being a parent content table and
another being content_news. content_news contains a FK
(content_news.content_id) that points to the content.id col. I found
that I can make changes on a ContentNews object and have them persist
to the proper fields in the content table. However, save and new do
not seem to work. Here’s my AR object:

class Content < ActiveRecord::Base
set_table_name “content”
set_sequence_name “content_id_seq”
has_one :content_type, :foreign_key => “id”
end

class ContentNews < ActiveRecord::Base
set_table_name “content_news”
set_primary_key “content_id”
belongs_to :content, :dependent => true, :foreign_key =>
“id”

 # Makes sure the parent Content object is also deleted
 def after_destroy
     if self.id != nil : content.destroy end
 end
 # Makes sure a parent Content news is created and gives out its id
 def before_save
     if self.id == nil : self.id=content.id end
 end

end

While the above requires more typing, it does seem to work (so far).
Ideally it would be nice to just automagically have Rails do this for
me, but again, it doesn’t seem that CTI support is in the code base
yet (here’s the ticket #: http://dev.rubyonrails.org/ticket/600 )

I think in the ticket there was talk about being able to also look
at, say, Content attributes and then be able to get a hold of the
relevant child object - this may be tricky if you have multiple child
object types, not sure as I’m still somewhat new to Ruby/Rails. For
my case, I always go child → parent, so that’s not really an issue
for me now.

If you (or anyone) sees any issues with the above, please let me
know. I might, some day, switch to STI, but honestly in my case where
we’ll keep adding different content types with their own attributes
(could be a dozen or more at some point), it doesn’t make sense for
me to use STI and keep adding columns on to one table - depending on
the required attributes, said table could be really big. The Agile
Web D. with Rails book has a few paragraph blurbs about what
you could try if STI doesn’t work for you (pg. 266). But, it’s just
that, a quick paragraph, so there’s no real in-depth like the other
stuff.

If you do find a different, more generic way than I have mentioned,
please share it with the list. Thanks.

-jason

On 11/25/05, Vlad Z. [email protected] wrote:

Hi all!

Short version: DRY principle. Don’t copy table attributes from contents
table to article_contents.

P.S. Sorry for my English.

BTW, your English was very good. I got it on the first reading.

I, too, am looking for a similar solution, because of the DRY principle.

Ed