Head London

Testing Single Table Inheritance Models in Ruby on Rails

Thursday 24th May 2007

I 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.

Tag Clouds in Ruby on Rails using has_many_polymorphs

Saturday 31st March 2007

Recently I was faced with a somewhat strange problem – I wanted to tag the same model with two different kinds of tags. Each Event needed to have both a regular Tag for categorization, and a PlaceTag to indicate its location.

I was using the acts_as_taggable gem to do the categorization tag. When I started considering how to do the PlaceTag, I quickly realized that the overloads I’d need to add a PlaceTag to the same model were nonexistent. This, coupled with the fact that both the acts_as_taggable gem and the plugin of the same name couldn’t do the job (and seemed to be unmaintained lately), got me searching for a more flexible solution.

Bang! The has_many_polymorphs plugin by Evan Weaver to the rescue. He’s written a couple of excellent tutorials on how to use his has_many_polymorphs plugin to generate tag clouds, and the bonus for me is that it should be easy to get my PlaceTag set up. The main trouble became tag cloud UI code generation, since the tag cloud code I had been using didn’t map exactly to the cloud structures generated by has_many_polymorphs.

My tag clouds were being generated by Tom Fakes‘ cloud code. Not wanting to cargo cult, I grabbed the Programming Ruby book and looked over the Blocks and Iterators section again (functional programming is amazingly concise but I sometimes don’t seem to have the six-dimensional brainiac capacities necessary).

In the end, I got to a solution which seems to work alright. I used the simplest possible Tag and Taggings models from Evan’s tutorials, so those models look like this:

/app/models/tag.rb:

[code]
class Tag < ActiveRecord::Base

has_many_polymorphs :taggables,
:from => [:events],
:through => :taggings,
:dependent => :destroy

def self.cloud(args = {})
find(:all, :select => 'tags.*, count(*) as popularity',
:limit => args[:limit] || 5,
:joins => "JOIN taggings ON taggings.tag_id = tags.id",
:conditions => args[:conditions],
:group => "taggings.tag_id",
:o rder => "popularity DESC" )
end

end
/app/models/tagging.rb:

class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :taggable, :polymorphic => true

def before_destroy
# disallow orphaned tags
tag.destroy_without_callbacks if tag.taggings.count < 2
end
end
[/code]

The relevant controller code for my index page, which is found in /app/controllers/home_controller.rb:

[code]class HomeController < ApplicationController

def index
@cloud = Tag.cloud
...
end

end
[/code]

In my case, the tag cloud is displayed in the home layout view, /layouts/home.rhtml, but the tag cloud itself is a shared partial so that it can be re-used throughout the app. The relevant tag cloud code for inclusion in home.rhtml is simply:

[code]
<%= render(:partial => "shared/tag_cloud", :o bject=> @cloud) %>
[/code]

The tag cloud partial itself is a slightly modified version of the same thing originally written by Tom Fakes, like so:

/app/views/shared/_tag_cloud.rhtml:

[code]
<% if tag_cloud.length > 0 %>
<% build_tag_cloud(tag_cloud, %w(cloud1 cloud2 cloud3 cloud4 cloud5 cloud6 cloud7 cloud8 cloud9)) do |tag, cloud_class| %>
<%= link_to(h("#{tag}"), tag_item_url(tag), { :class => "#{cloud_class} ", :style => "margin: .15em" } ) %>
<% end %>
<% else %> No tags found.

<% end %>
[/code]

Finally, I put the code that actually figures out the style for each tag in /app/helpers/application_helper.rb so that it's accessible from anywhere in the application. This was the part that drove me to re-read Blocks and Iterators:

[code]
module ApplicationHelper

def build_tag_cloud(tag_cloud, style_list)
max, min = 0, 0
tag_cloud.each do |tag|
max = tag.popularity.to_i if tag.popularity.to_i > max
min = tag.popularity.to_i if tag.popularity.to_i < min
end

divisor = ((max - min) / style_list.size) + 1

tag_cloud.each do |tag|
yield tag.name, style_list[(tag.popularity.to_i - min) / divisor]
end
end

# Create a link to a tag's view page.
# this could easily be different in your application, depending on how you structure your tag searches,
# but it seems smart to include it here as my tag cloud code depends on it. Change the tag_item_url in
def tag_item_url(name)
"/search/by_tag/#{name}"
end

end
[/code]

It seems to do the trick. Thanks to Evan and Tom for doing 90% of the work!

No wmode please, we’re British! AKA the @ key flash bug

Friday 2nd June 2006

We ran into a major problem last night when deploying http://www.englandallstars.com

The swf in question contained a form allowing users to type in email addresses. The trouble was that anyone with a British keymapping, using the Firefox browser, got a US English keymapping on text entry. This meant that users wanting to type email@domain.com ended up typing email”domain.com instead. If users happened to know that the ‘@’ symbol is over the ‘2′ key on a US keyboard, they’d figure it out, if not they’d be left scratching their heads.

We scratched our heads too.

It worked fine in Internet Explorer, the problem only occurred in Firefox (with Flash Player 8 ). The SWF had been exported using Flash 8 Pro, on a Mac G5. The keymapping preferences on that machine were set to British, although for whatever reason this particular G5 was still effectively using a US English keymapping. Weird. The SWF had also been compiled repeatedly using MTASC on Windows and Linux before final export was done from Flash on the Mac (so that all the fancy fonts showed up properly).

It turned out that the problem had nothing to do with the way the SWF was produced. After a few hours of experiments, we figured out that the problem was some wmode code on the embed tags:

[code][/code]

Deleting the wmode=”transparent” solved the problem, for both SWFObject and standard Macromedia embeds. If you have a British keymapping, you can see this behaviour at our wmode bug documentation page (users with US English keymappings won’t notice the problem). It would be interesting to know if other keymappings suffer from the same problem. Anybody want to let us know?

Late Binding of C# objects from NHibernate into the ASP.NET DataGrid control

Wednesday 26th April 2006

It’s not a full example with code downloads, but here’s an example of late binding in C#, when we don’t know whether a class being bound into a DataGrid is going to be of type Article, Vacancy, Image, or whatever. I’ve found this to be a good approach when customizing a DataGrid that we can re-use in our internally-developed content management system.

Since the objects we get back from NHibernate, wonderfully enough, are just objects of the type we ask for instead of some stupid intermediate typeless object contained in a DataSet, we can just bind them into the DataGrid. The one thing that’s necessary is that we need to know anything going into the DataGrid needs to implement certain properties, like Title and Active.

First, we define an interface that content objects must implement:

Read the rest of this entry »

(My) License Confusion and the Flash Org Revolution

Friday 24th March 2006

The world of Flash Actionscript has seen a lot of changes in the last year. If this was any other year in Flash’s ten-year history as an interactive animation app, I’d probably be referring to the release of Flash 8, talk about its features, and convey my excitements and fears about the new release.

However, in my world, this is the year of OSFlash. There has been something of a revolution among serious Actionscript coders, and many people are now developing and using Free, Libre and Open Source Software (FLOSS) Actionscript tools instead of grumbling about missing features in the We’re Here forums. An incredible number of initiatives has opened up a whole new world of Actionscript-based development: MTASC / Eclipse, ASWing, ActionStep, Red5, and many of the other projects on http://osflash.org are really making me fall in love with the SWF all over again.

It’s also got me fired up to release code under Free Software or Open Source licenses. The trouble is – which ones? What do I do about code that mine depends on that has an unknown license? Can I release this source once under the Mozilla Public License and then release a full application containing the same code under the GNU General Public License? Can I distribute an FLA that contains Macromedia components? And how does my code (potentially released as Free Software) relate, legally speaking, to the Macromedia class library on which it depends?

As a concrete example, I’d like to release the source code to the .SWF file at the top of this blog entry. There are a bunch of issues with it.

  • It uses some Macromedia components, namely the Button, the TextInput, and the ComboBox.
  • It depends on the MM class library. Does this affect whether it can be released under the GPL or MPL?
  • It uses the glorious AnimationPackage for the animation effects. Since AnimationPackage is licensed under the MPL, does this mean my code must be licensed the same way? Keep in mind that my code can’t function without it.
  • AnimationPackage itself relies on the work of two other developers, neither of whom have put any FLOSS licensing in place on their code. The http://dembicki.org has no licensing info at all, while the http://gskinner.com code specifically states that the code can’t be redistributed. I’m not using the GSkinner code, my mini-app just uses the Macromedia EventDispatcher class instead, but the licensing question remains somewhat the same.

Beyond the questions of reliance on code libraries, there is also the question of what I want to do with my code.

First, I’d like to release this Actionscript class, waterfall.as, under a BSD-style or MPL-style license, as a standalone thing that other developers can use, including in commercial projects, without the resulting apps necessarily needing to be Free Software. However, the code is also part of a larger application we have in development, which is a database-driven photo-display software rather like our project at http://www.bankfashion.co.uk I’d like this application to be GPL if and when we release it, so that if other companies start using and developing the code further, we see some benefit here at Headlondon. Can I release the same code under both licenses?

I’ll be exploring these questions over the next few weeks, and will post the results on this blog. And eventually, there will be a torrent of source available from our Flash development projects.