Caching slow ORM operations - Ramaze/ramaze GitHub Wiki

Depending on what you use in your model, it might slow down your application quite a bit.

For instance, let's say you're writing an email account management application. Your users are stored in a database, but quotas for instance are only known by your IMAP server. If you cant to provide quota lookup methods in your model, you are forced to query your IMAP server for this :

# Lookup quota for current user on IMAP server
# IMAPSERVER is a constant containing an Net::IMAP
# object (already connected with admin credentials)
def quota
  IMAPSERVER.get_quota_for(self.username).to_i
end

This simple lookup is rather long, and will make page display crawl when showing several users (in a table for instance).

One option, in this case, is to use Ramaze caching facilities to keep track of user quotas, and use memoization techniques to the cached data.

First, configure caching, telling Ramaze which cache backend you want. This must be done once for all (i.e. in some config file required by app.rb, not in the "quota" user model method).

Then, you have to tell ramaze that we want an 'imap' caching facility. Ramaze will create some kind of 'handle' for you that you can use whenever you need :

# Create an 'imap' handle for later use
Ramaze::Cache.options.names.push(:imap)
# Use Redis for all operations on 'imap' handle
Ramaze::Cache.options.imap = Ramaze::Cache::Redis

We can now use Ramaze::Cache.imap in our model to store or retrieve data from the Redis cache :

def quota(opts = {})
  # :refresh => forces a quota fetch from the IMAP server (default:
  # false)
  # :ttl     => how long do we want the cache to hold the cached
  # quota value (in secs, default: 1 day)
  options = { :refresh => false,
              :ttl     => 86400 }.merge!(opts)

  # Let's fetch the curretn cached quota for this user
  quot = Ramaze::Cache.imap.fetch("#{self.username}.imap.quota") 

  # If we are forced to refresh, or if we didn't find any cached
  # quota for this user, let's fetch it from the real IMAP server
  if !quot or options[:refresh]
    quot = IMAPSERVER.get_quota_for(self.username).to_i
    # We store the value in the cache for later use
    Ramaze::Cache.imap.store( "#{self.username}.imap.quota",
                              quot,
                              options[:ttl])
  end

  # Return the quota
  quot
end

The quota is fetched from the real IMAP server if it's not in the cache. Otherwise, the cached value is returned. While this won't speed up the first lookup, subsequent ones will be lightning fast until the cached quota expires.