Hello,
I’m creating my own Tumblr [tumblr.com] like rails app.
It’s like a blog, but in this case a blog post could be of a certain
type, i.e. a regular post, a video, a link, a photo, a song(info).
Well now, it’s clear that they share a lot of similar functionality:
title, created_at/updated_at, commentable, probably has an author_id,
etc…
But besides that they are very different: a post has a large text field,
a link has an url and a description and a photo a reference to the file
in a way.
What to choose? Single Table Inheritance? Not really an option since the
post types are very different.
A polymorphic relation mabye, with a Post; has_one :subtype,
:polymorphic => true;
And that’s what I did, but soon enough I saw that it gave me a lot of
problems.
First of all, it’s not really a subtype, in this case :subtype is really
a child model. When I have a post of type link, I would access the title
through @post.title, but the url and description through
@post.subtype.url and @post.subtype.description accordingly.
Not really nice, but with some nifty method_missing handler I made it a
bit easier.
Now when I only want to have posts of type link I could do Link.find and
I would have only links. But that one behaves so much different from
working from Post as in this case I would read the attributes like
@link.url, @link.description, @link.post.title
Not very consistent, at all.
So I use Post.find :all, :conditions => {:subtype_type (bad naming, I
know) => ‘Link’
To ease that I made a custom find method to accept Post.find :all, :type
=> :link and all was happy.
Sorry for the long post, it’s been on my mind for such a long time
already.
Anyways…
I was very proud on how I got it to work. Only instead of a Link.find
:all I had to do a Post.find :all, :type => :link, and most was based
around that. I could accept that, even though it was hard give up to. It
required some more hacking to enable easier Post creation of a certain
type and made my Post class bits by bits uglier to make it ‘easier’ to
work with.
But then after a while I wanted to add a relationship to Artist with
post of type song.
But how!?! I couldn’t just link the relationship between Artist and
Song, as that would mean would have the same effect as before. That I
don’t get posts of type Song, but pure song models instead, with all the
incosistent use as before.
And a relation between Artist and Post where the foreign key lies in
Song is not possible in rails. And I thought by myself “who the fuck
wants to make such a complex database model, the eediot!!”
At this moment I KNEW this is a flawed model too! And I’ve been thinking
and wandering and whining and crying since then. Not knowing how to
elegantly solve this stupid problem of mine.
STI in rails works really nice! It wouldn’t have any of these problems I
just described above, so why can’t I make how STI models in rails work
using multiple tables. That would be really nice and I believe this
would actually be a feasible.
the Post table would be the same as with a STI model (id, title,
created_at, updated_at, title, type) but the subtypes with have their
own table, the links table would look something like (post_id, url,
description) and the songs table something like (post_id, artist_id,
…).
The subtypes don’t need an id column, as they don’t, won’t and shouldn’t
be models themselves.
As with polymorphic relations, eager load is not an option. I can’t load
the url and description info from the links table as I don’t know what
type the post will be at query time. Well, has_many_polymorphs
[blog.evanweaver.com/pages/has_many_polymorphs] has some nice magic on
this as long as you know (define) what subtypes there are. But even
then, without eager loading I would be quite happy.
Quite happy? I will probably jump for joy!!
Thank you for reading, how are your thoughts on this?
Dax H.