Skip to content

Instantly share code, notes, and snippets.

@solotimes
Created May 12, 2011 03:01
Show Gist options
  • Save solotimes/967860 to your computer and use it in GitHub Desktop.
Save solotimes/967860 to your computer and use it in GitHub Desktop.
Some Mongoid extensions I made, to be moved to a repository soon (with tests etc..)
module Mongoid
# Caches the entire document in a Marshall and Redis.
# Defines Document#get(id), adds methods to recache document after a save.
# Add `include Mongoid::CachedDocument` in your model to enable the feature.
module CachedDocument
def self.included(base)
base.class_eval do
include InstanceMethods
extend ClassMethods
before_save :refresh_cache
class_inheritable_accessor :cached_fields
self.cached_fields = [:id]
delegate :cached_fields, :to => "self.class"
end
end
module ClassMethods
# Defines what fields can be used with cached_find (others than 'id' which is automatically added)
# Remember to set indexes !
def cache_on(array)
array.each do |field|
cached_fields << field
end
end
# Get a document from an +field+==+value+ with Redis, or request the database.
# IE: User.cached_find(:login, 'hello')
def cached_find(field, value)
field = field.to_s unless field.class == String
raise "#{field} is not in cache_on" unless cached_fields.include?(field.to_sym)
# Trying to get the value from Redis
cache_hit = true ; cache_get = false
begin
redis = REDIS.get("#{self.name}:#{field}:#{value}")
rescue Errno::ECONNREFUSED
# Do nothing
end
if redis
begin
obj = Marshal.load(redis)
rescue TypeError
# Do nothing. In this case we suppose the cache was corrupted.
end
else
# Querying Mongo and set the cache for later use
cache_hit = false
query_field = '_id' if field == 'id'
obj = self.where(field => value).first
cache_get = true if obj && obj.refresh_cache
end
return obj
end
end
module InstanceMethods
# Dump the object in the cache.
def refresh_cache
begin
cached_fields.each do |field|
puts "Setting for #{field}"
value = self.send(field)
REDIS.set("#{self.class.name}:#{field}:#{value}", Marshal.dump(self))
end
true
rescue Errno::ECONNREFUSED
Merb.logger.warn "REDIS - Connection Refused"
false
end
end
end
end
end
module Mongoid
# User.cache_get_avatar_from_id("4ad937f9957ba40429000001")
module RedisCache
def redis_cache(key, value)
mkey = key == :id ? '_id' : key.to_s
class_eval <<-RUBY, __FILE__, __LINE__+1
def self.cache_get_#{value}_from_#{key}(rkey)
# Trying to query from Redis first
cache_get = false ; cache_set = false
begin
redis = REDIS.get("#{self.to_s}:" + rkey + ":#{value}")
cache_get = true
rescue Errno::ECONNREFUSED
end
# Querying Mongo and set the cache for later use
unless redis
conditions = {}
conditions["#{mkey.to_sym}"] = rkey
redis = self.where(conditions).first
redis = redis.send("#{value.to_sym}") if redis
cache_set = true if redis && cache_set_#{value}_from_#{key}(rkey, redis)
end
return redis
end
def self.cache_set_#{value}_from_#{key}(rkey, result)
begin
redis = REDIS.set("#{self.to_s}:" + rkey + ":#{value}", result)
return true
rescue Errno::ECONNREFUSED
return false
end
end
RUBY
end
end # RedisCache
end # Mongoid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment