Testing Single Table Inheritance Models in Ruby on Rails
Posted by Dave Hrycyszyn 24th May 2007 in Ruby on RailsI 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:
class Content < ActiveRecord::Base
end
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:
class Article < Content
end
class Page < Content
end
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:
class Content < ActiveRecord::Base
set_table_name “content”
end
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:
article_one:
id: 1
title: foo
body: this is a body
type: Article
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.
Search
Categories
- News
(41)
- Victoria’s Secret
(7)
- Stu's View
(3)
- Design
(13)
- Technical
(11)
- Actionscript
(3)
- GNU / Linux
(4)
- FLOSS
(7)
- C# / .NET
(2)
- XHTML / CSS
(1)
- Agile Development
(2)
- Joeys Corner
(4)
- Sleeping Stu
(2)
- The Hoseclamp's Notebook
(13)
- Ruby on Rails
(3)
Monthly Archives
- September 2008 (1)
- August 2008 (1)
- July 2008 (1)
- June 2008 (1)
- May 2008 (2)
- March 2008 (1)
- February 2008 (1)
- January 2008 (1)
- November 2007 (2)
- August 2007 (1)
- May 2007 (2)
- April 2007 (5)
- March 2007 (12)
- February 2007 (10)
- January 2007 (4)
- November 2006 (2)
- September 2006 (4)
- August 2006 (1)
- July 2006 (1)
- June 2006 (6)
- May 2006 (2)
- April 2006 (4)
- March 2006 (14)
- February 2006 (12)
- January 2006 (1)
- December 2005 (1)
- November 2005 (1)
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.