Monday, March 17, 2008

Single Table Inheritance With Nested Classes in Rails

There's a feature in Rails, which allows you to have several classes on the same table. You define a string column named 'type' and then inherit your new classes from the basic unit class. Pretty simple and sometimes very useful. It's called Single Table Inheritance or simply STI.

But in some cases there are might be quite a number of subclasses and you may even don't know how many of them will be. Say a simple case. You've got a class Game which presents a basic game model data-structure, and then you've got several subclasses which represents real games logic which have just the same data-structure but different behavior. The customer said I want those five games now and probable another good five later.

Ok, that's fine and probably an excellent opportunity for using the STI feature. But the thing which bothers me in the case is the big and unpredictable number of subclasses, and as for me, I would like to not have such a mess in my app/model/ directory.

A possible solution is in having nested subclasses for the Game class. In general it might look like this

class Game < ActiveRecord::Base
#........ some basic crap .........

class Klondike < Game
end

class Poker < Game
end
end

Then, when you create instances of the subclasses you'll have the 'type' attribute set properly to the name of the subclass.

>> g = Game::Poker.new
>> g
=> #<Game::Poker type: "Poker", ....>

This will work just the same way if would define a usual class like class PokerGame < Game, but this solution with nested classes allows you to organize your subclasses better. Now you can, by following the rails naming convention, create the following directories/files structure

app/
models/
game/
klondike.rb
poker.rb
game.rb

and then inside, say, the poker.rb file define your nested classes like that

class Game::Poker < Game
....
end

In such a way you'll keep your subclasses organized well and still will be able to use the STI feature.