Active Record Query Caching with Sinatra and multiple Databases

rob 15 Apr 2011
?

This one is a pretty specific hack. I’ve had the need to build mini reporting apps, using Sinatra, that aggregate data from multiple databases and produce a report. This is all fine since ActiveRecord is awesome, but I’ve always missed AR’s query caching ability.

After some digging I found that query caching is only enabled on AR’s Base connection and all other models must use that awkward Model.cache{} construct – which is annoying to use. I’ve hacked up a solution that works, although it relies on :send and instance_variable_set which isn’t very elegant or solid.

For what it’s worth, here is a “simple” way to get Sinatra to use ActiveRecord’s native query caching for more than 1 database:

Start’er up: $> open http://localhost:9292 && rackup and you should see “Hack0rific!” – now check out the log and see how AR cached and didn’t cache, it should resemble:

[2010-03-24 15:12:46] INFO  WEBrick::HTTPServer#start: pid=15801 port=9292
  SQL (0.2ms)   SET SQL_AUTO_IS_NULL=0
  SQL (0.2ms)   SET SQL_AUTO_IS_NULL=0
-- enabling up per-model query caching --
  MySQL::User Load (0.4ms)   SELECT * FROM `user` LIMIT 1
  CACHE (0.0ms)   SELECT * FROM `user` LIMIT 1
  ...a few more times...
-- disabling up per-model query caching --
  MySQL::User Load (5.3ms)   SELECT * FROM `user` LIMIT 1
  ...a few more times...

The one big caveat is that you need to enable_query_caching after the connection has been made (otherwise AR’s establish_connection will override your hacks) – so it needs to be in an initializer or something similar.

I’ve had great success with this in some apps, although it works a little too well so updates don’t push through when they need to. Take it for what its worth, a silly hack, and let me know how it works out for you :).