Ultracache

Ultracache provides model-level interfaces for better abstraction of your cached data. You can organize and store/fetch cached data easily through the provided interfaces. You can boost up the response time of your actions through appropriate caching of persisted data.

Ultracache uses a conventional key-value store as its backend. Currently it only supports Redis, but we are planning to include other storages like Memcached into our feature set.

Installation

Add Ultracache to your Gemfile.

gem 'ultracache'

Or, install Ultracache manually with Rubygems.

Configurations

Generate an initializer for Ultracache in config/initializers/ultracache.rb.

# config/initializers/ultracache.rb

Ultracache.config do |config|
  config.storage = Ultracache::Storage::Redis.new(:urls => ['localhost'])
  config.serializer = Ultracache::Serializer::JsonSerializer.new
end

Usage

Ultracache associates cache with your model objects. Model objects can have cached attributes or queues of other cached models. You can decide appropriate method for caching which meets your requirements.

Cached Attributes

You need to mixin Ultracache::Cached module into your model objects to which you want to associate your cache.

Cached attributes is the simplest form to associate caches with your models. Here's an example:

class Person
  include Ultracache::Cached

  has_cached_attribute :cached_colleagues do |obj|
    obj.colleagues.as_json(:with_contact => true)
  end
end

Keep in mind that return value of presented block is serialized to a string by the serailizer specified in configurations. If block is not presented, Ultracache tries to serialize the object with as_json method.

class Person
  include Ultracache::Cached

  has_cached_attribute :serialized_string # Objects are serialized with Person#as_json
end

Cached attributes are useful when cost to generate the desired data is high, like JSON serializations. Once we have noticed severe performance degradation caused by plain JSON serializations.

Cached Queues

Cached queue is suitable when your actions require collection of objects, like the most index actions. Like has_many relationship of ActiveRecord, cached queues are made from a relationship of two model classes.

class Person
  include Ultracache::Cached

  has_cached_queue :notifications
end

class Notification
  include Ultracache::Cached

  cached_queue_in :person do |obj|
    {
      :id => obj.id,
      :content => obj.content
    }
  end
end

Cached queues are especially useful when cost to fetch additional data from your persistent storage is significantly high. Queuries including referenced relationships of MongoDB or heavy join operations fit for this type of concerns.

p = Person.find params[:id]
notifications = p.notifications

Note that entries in queues are stored as string. If you want to fetch or modify part of the model objects, you need to deserialize them.

p = Person.find params[:id]
notifications = p.notifications :deserialized => true

notifications.first['content'] # Content cached in your queue previously

Keeping them with Integrity

Lifecycle of caches generated by Ultracache are synchronized with it of model objects. Ultracache adds save_cache, update_cache, destroy_cache methods to models which include Ultracache::Cached. These methods are registered as ActiveModel callbacks semantically corresponding to each method.

By default, contents of cached attributes are updated along with status of model objects they belong to. On the other hand, you can decide whether entries in cached queues are updated or not.

Further Documentations

Refer comments in source files for more detailed information. We are preparing detailed documentations which will be published soon.