I have a card-game application which makes use of Single Table Inheritance. I have a class Card
, and a database table cards
with column type
, and a number of subclasses of Card
(including class Foo < Card
and class Bar < Card
, for the sake of argument).
As it happens, Foo
is a card from the original printing of the game, while Bar
is a card from an expansion. In an attempt to rationalise my models, I have created a directory structure like so:
app/
+ models/
+ card.rb
+ base_game/
+ foo.rb
+ expansion/
+ bar.rb
And modified environment.rb to contain:
Rails::Initializer.run do |config|
config.load_paths += Dir["#{RAILS_ROOT}/app/models/**"]
end
However, when my app reads a card from the database, Rails throws the following exception:
ActiveRecord::SubclassNotFound (The single-table inheritance mechanism failed to locate the subclass: 'Foo'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite Card.inheritance_column to use another column for that information.)
Is it possible to make this work, or am I doomed to a flat directory structure?
Probably the best way to do this would be to nest the Foo
class inside a BaseGame
module.
A ruby module is roughly similar to a package structure in other languages, it's a mechanism for partitioning related bits of code into logical groups. It has other functions such as mixins (which you can find explained here: http://www.rubyfleebie.com/an-introduction-to-modules-part-1/) but in this instance they're not relevant.
You'll need to reference and instantiate the class slightly differently. For example you'd query it like this:
BaseGame::Foo.find(:all,:conditons => :here)
Or create an instance of it like this:
BaseGame::Foo.new(:height => 1)
Rails supports modularized code for Active Record models. You just need to make a few changes to where the class is stored. say for example you move the class Foo into a module BaseGame (as in your example), you need to move apps/models/foo.rb
to apps/models/base_game/foo.rb
.So you're file tree will look like:
app/
+ models/
+ card.rb #The superclass
+ base_game/
+ foo.rb
To declare this on the class define like so:
module BaseGame
class Foo < Card
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With