Skip to content

Instantly share code, notes, and snippets.

@robhurring
Created March 24, 2010 19:00
Show Gist options
  • Save robhurring/342648 to your computer and use it in GitHub Desktop.
Save robhurring/342648 to your computer and use it in GitHub Desktop.
Sinatra using ActiveRecord's Query Caching ability across multiple Databases : http://proccli.com/active-record-query-caching-sinatra-multiple-databases
require 'sinatra_query_caching_demo'
run Demo
require 'rubygems'
require 'sinatra/base'
require 'active_record'
require 'logger'
# override some instance variables and _force_ query caching to be enabled on databases other than AR::Base's connection
module ARQueryCachingHack
def self.included(klass)
# make sure you call this _AFTER_ a connection has been established, otherwise the connection
# will override these. it is kind of a pain, so the best bet is to include this in the initialization
def klass.enable_query_caching
self.connection.instance_variable_set(:@query_cache_enabled, true)
self.connection.instance_variable_set(:@query_cache, {})
end
def klass.disable_query_caching
self.connection.instance_variable_set(:@query_cache_enabled, false)
end
end
end
ActiveRecord::Base.configurations = {
# this is a garbage connection so we can make sure AR::Base is on a different connection. If we are sharing
# the connection it kind of renders this moot since AR::Base is always query cached with the AR::QueryCache
# middleware
'test' => {
'adapter' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'testing' # change this to some other DB besides +mysql+
},
# our separate target database. if we are on an app that uses multiple DB's then this would be the +other+ db, not
# AR::Base
'mysql' => {
'adapter' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'mysql'
}
}
# AR::Base needs a connection before AR::QueryCache can take effect
ActiveRecord::Base.establish_connection 'test'
ActiveRecord::Base.logger = Logger.new($stdout)
# just to keep things separate, tuck all external models in their own module
module MySQL
# this would be a common base for all models that need a different DB, since all AR:Base models will just
# inherit from AR::Base
class Base < ActiveRecord::Base
self.abstract_class = true
establish_connection 'mysql'
end
# some model in a different database
class User < Base
include ARQueryCachingHack
set_table_name :user
end
# enable query caching on each model you want
def self.query_cache_models
[User].each &:enable_query_caching
end
end
class Demo < Sinatra::Base
use ActiveRecord::QueryCache
before do
# enable query caching by default. this probably isn't where you _want_ to put this, an initializer is probably best
MySQL.query_cache_models
ActiveRecord::Base.logger.info '-- enabling up per-model query caching --'
end
get '/' do
# with query caching
10.times{ MySQL::User.first }
# => CACHE (0.0ms) SELECT * FROM `user` LIMIT 1
# without query caching
ActiveRecord::Base.logger.info '-- disabling up per-model query caching --'
MySQL::User.disable_query_caching
10.times{ MySQL::User.first }
# => MySQL::User Load (0.3ms) SELECT * FROM `user` LIMIT 1
"Hack0rific!"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment