sexta-feira, 23 de janeiro de 2009

Cuidado ao cachear named_scope no Rails

Deve-se tomar cuidado ao cachear o acesso a um named_scope pois ele tem um carregamento de forma preguiçosa, o famoso lazy load. Assim, o código abaixo gravaria no cache não os atores femininos, mas sim todos os atores.

class Filme
#...
def atores_femininos_cacheado
Rails.cache.fetch("#{self.id}:atores-principais") { self.atores.femininos }
end

class Ator
#...
named_scope :femininos, :conditions => { :sexo => 'F' }

Se você observar o log, verá que o rails executará a query sem as condições definidas na classe Ator para o named_scope :femininos. E que após ser cacheado, será essa a query que deixará de ser executada.

A query para buscar atores femininos do named_scope só será realmente executada quando algum método do objeto retornado pelo método .atores.femininos for chamado. Veja no exemplo abaixo:

@filme = Filme.find_by_id 10
filme.atores_femininos_cacheado.last

Ou seja, o cacheamento não está servindo ao propósito definido. Uma solução para isso é cachear diretamente o resultado de um find, como pode ser visto abaixo:

class Filme
#...
def atores_femininos_cacheado
Rails.cache.fetch("#{self.id}:atores-principais") do
Ator.find_all_by_filme_id self, :conditions => { :sexo => 'F' }
end
end

2 comentários:

  1. Fala Tiago,

    Você pode usar o all, dos named scopes também, que força a "consulta" (preenchimento do proxy):

    self.atores.femininos.all

    []'s

    ResponderExcluir
  2. bem fixe o teu blog :)

    bem deixo te aqui o meu que acabei de fazer a pouco tempo ;)

    http://programandoemportugal.blogspot.com/

    ResponderExcluir