On Rails 2.0, SQL Server adapter, gems, vendor and load paths

Over the last few days I have been moving the BiQ application to Rails 2.0 PR. I’ve so far run into a fair deal of issues; one annoying one that I figured I’d share.

The gist of the matter is that creating some of my models failed in some cases. It appeared to be primarily when the save triggered an insert into another table as well.

Digging around a bit, I traced it down to the fact that the newly created model was given an id that didn’t match the id in the database. The reason for that turned out to be quite the sneaky little bastard…

First a few important facts

All of this is perfectly fine and working in the majority of cases. However looking at the log for the failing test cases, the following line stood out like a pimple on a babys bottom:

CACHE (0.000000) SELECT @@IDENTITY AS Ident

No wonder I am getting wrong ids for my models when ActiveRecord is returning a cached value (ie the id of the first inserted model).

However, it seemed odd that it would even be able to get a cached value, since the query immediately before the cached one is an insert statement. And as mentioned above, the query cache is cleared after an insert, so the cache should be perfectly clear at that point.

Digging vendor

Digging into my vendored Rails directory (much love for /vendor), it slowly became obvious that clear_query_cache was never actually called as part of that insert. Digging a bit further, it appeared insert_sql of my SQLServerAdapter wasn’t called at all.

At this point I was highly confuzzled – even more so after verifying that the SQLServerAdapter in /vendor is indeed loaded and used. Getting desperate, I searched the entire application and ruby directory for occurrences of @@IDENTITY, found 2 relevant ones and replaced each with a bogus statement.

Lo and behold, I got an exception from ActiveRecord with a stack trace clearly telling me that it was raised in my gems directory. Rails was using the SQLServerAdapter from the installed, old ActiveRecord gem for doing the insert – a version of ActiveRecord that naturally has no idea that a query cache even exists. Not only am I confuzzled, Rails is as well.

Resolution

And I don’t blame it. My loading of the SQL Server Adapter was highly unorthodox it appears. In the end, all I have to do to make it work is make sure I’ve added my vendored SQLServerAdapter to my loadpaths:

# Add additional load paths for your own custom dirs
config.load_paths += %W( #{RAILS_ROOT}/vendor/activerecord-sqlserver-adapter/lib )

Hey, I even learned something

Gotta love these things. I did, however, learn a few things from this debacle:

Back to rewriting my fixtures to go with the Foxy Fixtures style, mmmmm.