Conhecendo as opções de cache do Rails 2.1


Leia em 2 minutos

O Ruby on Rails[bb] 2.1, dentre outras novidades, trouxe suporte nativo a cache, com diversas opções de armazenamento. O destaque vai para o suporte ao Memcache, de longe uma das opções mais utilizadas. Todas essas novidades foram adicionadas ao módulo ActiveSupport::Cache, que você confere neste artigo.

Configurando as opções de cache

Para definir qual o tipo de cache que você quer utilizar, altere a nova configuração cache_store, adicionada aos arquivos de ambiente de sua aplicação no diretório config/environments/*.rb. Você pode escolher entre :memory_store, :file_store, :mem_cache_store e drb.

config.cache_store = :memory_store
config.cache_store = :file_store, '/path/to/cache'
config.cache_store = :mem_cache_store
config.cache_store = :drb_store, "druby://localhost:2250"
config.cache_store = :mem_cache_store, '127.0.0.1:11211', '127.0.0.1:11212', {:namespace => 'myapp'}

A opção padrão de cache é :memory_store, a menos que o diretório tmp/cache exista; neste caso, a opção utilizada será :file_store.

Vale lembrar que se você utilizar uma opção cujo ambiente não está funcionando corretamente, sua aplicação não deixará de funcionar. Este comportamento é perfeito para trabalho em equipe, onde um desenvolvedor pode configurar seu ambiente para utilizar o Memcache enquanto os outros não precisam se importar com isso naquele momento.

Como funciona

Todas as funções de cache estão disponíveis no objeto Rails.cache. Para gravar qualquer coisa no cache você deve utilizar o método write.

Rails.cache.write('some_identifier', 'some_value')

Você pode passar qualquer valor para ser gravado no cache, incluindo objetos de ActiveRecord.

@user = User.first
Rails.cache.write(@user.cache_key, @user)

O ActiveRecord adiciona um método que gera uma chave única para cada objeto, chamado cache_key. Este método gera uma chave como "users/1-20080713185825", que você possa acessar e expirar o objeto sempre que precisar. Por padrão, a chave gerada irá utilizar o nome do modelo, o id do objeto e a data de atualização, disponível através do atributo updated_at.

Para ler um objeto do cache, você pode utilizar o método read. Ele recebe um único argumento que identifica o objeto. Caso o objeto não seja encontrado, o valor nil será retornado.

Rails.cache.read('some_identifier')

Você pode verificar se um item existe no cache com o método exist?.

Rails.cache.exist?('some_identifier')

Você pode estar se perguntando se você precisa utiliza o método exist? juntamente com read e write para acessar um objeto caso ele exista e gravar um novo item caso ele não seja encontrado. Na verdade, você pode utilizar o método fetch que tenta acessar um item no cache e, caso ele não exista, executa o bloco que é passado e faz a gravação em cache automaticamente.

@users = Rails.cache.fetch('users/all') { User.all }

O método fetch pode receber um hash de opções. No momento, a única opção disponível é :expires_in, que permite alterar o tempo de expiração do cache somente para aquele objeto.

@users = Rails.cache.fetch('users/all', :expires_in => 30.minutes) { User.all }

Para o caso de você estar acessando um único objeto, você pode sobrescrever o método cache_key de modo que ele não gere a chave com o a data de atualização.

class User < ActiveRecord::Base
  def cache_key
    "users/#{id}"
  end
end

Assim, você pode acessar os objetos de maneira mais simples. Veja um exemplo de como isso funcionaria em uma action do controller users.

class UsersControllers < ApplicationController
  def show
    @user = Rails.cache.fetch("users/#{params[:id]}") { User.find(params[:id]) }
  end
end

E se você segue a idéia de encapsular toda a lógica nos modelos, existe sempre a opção de cuidar do cache desta maneira.

class User < ActiveRecord::Base
  def self.find_recent_users
    Rails.cache.fetch('users/recent') { all :order => 'created_at desc', :limit => 10 }
  end
end

Você também pode remover qualquer item do cache com o método delete, que retorna true or false.

Rails.cache.delete('users/1')

Finalizando

É isso! Acredito que este artigo cubra as principais funcionalidades de cache que foram adicionadas à versão 2.1. Dúvidas, sugestões ou correções, envie um comentário!