Testing Single Table Inheritance Models in Ruby on Rails
Thursday 24th May 2007 at 6:30 pmI had a small problem today when trying to do unit testing of single-table inheritance models in Rails, all my tests initially failed and I wasn’t quite sure why. It’s a pretty simple fix but isn’t documented too well anywhere, so here’s the skinny.
My model structure was pretty simple, I had a Content class that acted as a base class for Article, Page, Event, and a bunch of others. So I added a Content class using a model generator, ending up with:
[code]
class Content < ActiveRecord::Base
end
[/code]
Then I added Article and Page classes using the model generator, and changed the default class definitions so that each of those classes inherited from Content. That looks like this:
[code]
class Article < Content
end
class Page < Content
end
[/code]
Then I ran my tests, expecting that the default “test_true” assertions were going to pass. Explosion!
The first problem was that I named my table “content”, not “contents”. Since this isn’t included in the pluralization rules for Rails, my model was trying to find a table called “contents”. This was easily fixed by changing the Content class like this:
[code]
class Content < ActiveRecord::Base
set_table_name "content"
end
[/code]
However, tests were still failing. After quite a bit of googling, it turns out that it was the auto-generated test fixture names that were the problem. First off, the articles.yml and pages.yml file were useless – when testing STI classes, you set up your fixtures in the superclass fixture definition. That is, in my case I only needed content.yml, and if I wanted to set up an Article fixture in there, it would look like this:
[code]
article_one:
id: 1
title: foo
body: this is a body
type: Article
[/code]
Note that I had to set the type property manually to the class name of the subclass object that the fixture is for. Note also the name of the fixtures file – because of my use of a table name for Content that’s not in the default pluralization rules, the fixture file needed to be content.yml rather than the default contents.yml.
One more thing and it all fell into place. All of the generated unit tests had incorrect fixture file names in them – content_test.rb had fixtures :contents, article_test.rb had fixtures :articles, and page_test.rb had fixtures :pages. All of these needed to be changed to fixtures :content before any of the tests would work. Rails apparently looks for a database table name matching the name of the fixtures file, so until I did this my tests were failing when looking for nonexistent tables.
Hopefully that will save someone from the horror of having to trawl the web using the keywords rails sti test.

Thanks, it helped
Wouldn’t it also have worked (with less work manually changing tests) to add a line to your inflections.rb like so:
inflect.uncountable %w( fish sheep content )
inflect.uncountable would do the job instead of set_table_name, yeah, but all the fixtures work is always necessary (so articles.yml is still useless, and you need to put your articles fixtures into the content.yml fixture with a type property, etc).
I have a problem in my test .
When launching the test on my model ‘Module’ inherited from a class ‘Application’ (the table applications exist in database)
My test tries first to clean the table ‘modules’ , that does not exist.
Did i miss something?
One thing that could cause this is if you forgot to change the
fixtures :modules
line from your test into
fixtures :applications # or whatever your table name is
@Laurent
Got the same problem. Turns out fixtures were generated for all models.
So for the table that is really there but also for the models which inherit from it, which obviously don’t have a table, as that is the whole point of STI.
The scaffold generator does create fixtures even if you specify –skip-migration it seems.
Wonderful journey and experience!
Appreciate it! Single table inheritance models blew up my unit tests starting out – thanks for the quick and easy fix.