Using a has_many association with a single table inheritance model in rails

3.5k views Asked by At

I'm trying to create a simple has_many association between my Game and DLC models. The challenge I'm facing is that since there's no DLC table because of the single table inheritance, there's no way to insert a game_id. So if I were to do the following I'd get this error:

game = Game.create
game.dlcs

SQLite3::SQLException: no such column: games.game_id

Here is how my models are currently setup:

class Game < ActiveRecord::Base
    has_many :dlcs
end

class DLC < Game
    belongs_to :game
end

Note: DLC refers to downloadable content

2

There are 2 answers

1
max On BEST ANSWER

The simplest alternative would be to just use self-joins and add a parent_id column to games.

class Game < ActiveRecord::Base
  has_many :dlcs unless self.name == 'DLC'
end

class DLC < Game
  belongs_to :game, foreign_key: :parent_id
end

If that's absolutely unthinkable you can create a join table.

# game_id: int
# dlc_id: int
class GameExtension
  belongs_to :game
  belongs_to :dlc
end

class Game < ActiveRecord::Base
  has_many :game_extensions
  has_many :dlcs, though: :game_extensions
end

class DLC < Game
  has_many :game_extensions
  belongs_to :game, though: :game_extensions
end
3
rossettistone On

Edit: This answer was based on a misunderstanding of the original question. OP has clarified that Download refers to DLC, and is in fact a decent case for STI.

It is not my intention to be contrarian, but I'm not sure I see the case for using single-table inheritance in this case. Single-table inheritance is best used when two models are extremely similar in terms of their database columns, yet appreciably different in the context of the application.

Hypothetical models called Cow and Horse might share the farm_animals table for example. You could even make Stallion a subclass of Horse. This would let you keep all of these models on one table while giving you the convenience of methods like Stallion.new, which is really just an abbreviation for FarmAnimal.new(type: 'horse', gender: 'male').

It's not clear to me that the same benefits are present here for the relationship between Game and Download. If I've missed something crucial, and am delivering useless information with this answer, my humble apologies! Otherwise, I'd suggest reevaluating the use of STI in this case.