2

This comes from the Rails world, but is a pretty generic question about Single Table Inheritance. They only reason I'm asking this is that people keep pushing STI on me when there is no obvious reason for it. May be I'm missing some point? Please consider these two scenarios for displaying & storing page contents for various pages on the website:

Scenario 1

class ContentItem < ActiveRecord::Base
  belongs_to category
end

Here all the possible items are stored in one table, only distinguished by the category. Then wherever you need to display all news items or faq items , you just do a call to category.

Scenario 2

class ContentItem < ActiveRecord::Base
  
end

class FaqItem < ContentItem
end

class NewsItem < ContentItem
end

Here there is no need for category, but if you ever need to add another type of ContentItem, you need to create another model, and another and so on.

My problem with scenario #2 is that FaqItem & NewsItems are exactly the same. They are never going to be different. The only difference is that they can be modified by different people ( Site Admin vs PR person for news) .

So while both approaches are ok, why choose one scenario over the other in this particular instance?

Community
  • 1
  • 1
konung
  • 6,908
  • 6
  • 54
  • 79

3 Answers3

2

If there are only a few categories or types, and a lot of code is shared, it is very manageable to put it in one class. But once the list grows, your code will be scattered with case statements or if-trees, and this is where inheritance comes in handy.

For instance:

def title
  case category_id
    when 'FaqItem'
      do_1_thing
    when 'NewsItem'
      do_another_thing
  end
end

as opposed to

class FaqItem < ContentItem
  def title
    do_1_thing
  end
end  

class NewsItem < ContentItem
  def title
    do_another_thing
  end
end  

The second solution will be more easily maintainable and understandable. There could be some duplication of code, but this could be solved by smartly using your parent class.

Still: it is a matter of taste how soon you switch to using STI, that will depend on the complexity of your code.

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • So essentially if there is no or very little extra functionality on the subclass, I might as well stick with one class. It's more of a personal choice, like whether you like escargot or not :-) – konung Nov 03 '11 at 14:10
  • I believe a lot of choices in programming are personal. STI (an Object Oriented approach) definitely has its merits, but is also more complex. So in very simple cases I would not use it. If you later get more different content items, you can always refactor to STI at that time. Code is not static, your choices don't need to remain permanent. Choose the simplest solution that works now, and refactor later if needed. – nathanvda Nov 03 '11 at 14:30
1

I'm not familiar with the term "Single Table Inheritance", but it looks like an instance of the standard argument about subclassing versus type codes. People argue about this because both options can be the correct choice, depending on the circumstances. My pragmatic advice is: pick whichever tactic leads to less code duplication, given the larger context. Consider not only the categories you have now but also the possibility of needing to add new categories in the future.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • That's my point exactly. This was just a simple example of what I'm working, but there are much more complicated models: Product for instance. And while ipod is different from portable cd player, if you are not storing and distinguising characteristrics ( such as cd player, doesn't have storage capacity), there is no point creating STI classes, for the sake of having sti classes. Just trying to see if I'm missing something here. – konung Nov 03 '11 at 04:06
1

I like to use STI in Rails when (a) you need some specific behavior in one or more subclasses and (b) you're going to be doing parent class and subclass finds in different parts of the app.

In the example you give, maybe all ContentItems will have a "title" attribute. But maybe the FaqItem also needs an "answer" attribute, and maybe the attribute is required via a validation.

Also, maybe your app will need an FAQ page with only the FAQs (FaqItem.all). But maybe it will also need a complete index page with all content items (or a search feature).

Stuff like that is where STI comes in handy.

(also don't forget to create an index on your type column)

Callmeed
  • 4,972
  • 5
  • 34
  • 49
  • All the instances you suggested can be easily handled by having category_id. – konung Nov 03 '11 at 14:00
  • PLease ignore previous comment. Thanks, callmeed, we considered that. All the instances you suggested can be easily handled by having category_id. So if you need things like FaqItems.all - you could use a scope on ContentItems, like scope faq, where(:category_id => Category.where(:name => "faq")). All ContentItems have title ("question"), body ( which can be treated as "answer"), and if you need and index page , you can just search on ContentItems. Plus it's much easier to add another category from admin itnerface, then to create a subclass, without involvement from the developer. – konung Nov 03 '11 at 14:06
  • Trying to see if there is something not obvious, that I'm missing. – konung Nov 03 '11 at 14:08
  • Ok, so I guess I thought you'd be using categories in a "topical" manner (e.g. "sports", "politics") not in a manner equivalent to STI's "type" field. But I suppose you could also implement tagging for topical stuff. I suppose it comes down to a style issue. – Callmeed Nov 07 '11 at 22:42