Pergunta

Eu estou trabalhando em um aplicativo de Rails, onde eu estou usando o cache de página para armazenar a saída html estática. O caching funciona bem. Estou tendo problemas com a expiração dos caches, no entanto.

Eu acredito que o meu problema é, em parte, porque eu não estou expirando o cache do meu controlador. Todas as ações necessárias para este estão sendo tratadas no modelo. Isso parece que deve ser factível, mas todas as referências a expiração de cache baseada em modelo que eu estou achando parecem estar fora da data, ou de outra forma não estão funcionando.

No meu arquivo environment.rb, eu estou chamando

config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )

E eu tenho, no um arquivo / pasta varredores, LinkSweeper:

class LinkSweeper < ActionController::Caching::Sweeper
  observe Link

  def after_update(link)
    clear_links_cache(link)
  end

  def clear_links_cache(link)
  # expire_page :controller => 'links', :action => 'show', :md5 => link.md5
    expire_page '/l/'+ link.md5 + '.html'
  end
end

Então ... por que não é eliminar a página em cache quando eu atualizar o modelo (Processo: usando script / console, eu estou selecionando itens de banco de dados e salvá-los, mas suas páginas correspondentes não está excluindo a partir do cache), e eu também estou chamando o método específico no modelo Fazer a ligação que normalmente invocar a vassoura. Nem obras.

Se é importante, o arquivo em cache é um hash MD5 fora um valor de chave na tabela de links. A página em cache está sendo armazenado como algo como / l / 45ed4aade64d427 ... 99919cba2bd90f.html.

Essencialmente, parece que a vassoura não é realmente observando o link. Eu também li ( aqui ) que pode ser possível simplesmente adicionar o varredor para config.active_record.observers em environment.rb, mas que não parecem fazê-lo (e eu não tinha certeza se o LOAD_PATH de app / varredores em environment.rb evitado isso).

Foi útil?

Solução

Apenas uma nota:. Você pode usar cache_sweeper em ApplicationController

class ApplicationController < ActionController::Base
  cache_sweeper :my_sweeper
end

class MySweeper < ActionController::Caching::Sweeper
  observe MyModel

  def after_update(my_model)
    expire_page(...)
  end
end

Outras dicas

Então, eu tentei um número de diferentes abordagens, para ver o que funciona eo que não funciona.

Mais uma vez, para resumir a situação: Meu objetivo é a expirar páginas em cache quando um objeto atualizações, mas a expirar-los sem depender de uma ação de controlador varredores convencionais usam uma linha no controlador para notificar. o varredor que ele precisa para funcionar. Neste caso, eu não posso usar uma linha no controlador, como a atualização está acontecendo dentro do modelo. tutoriais vassoura normais não estão funcionando, como eles presumem que a sua principal interação com o objeto de banco de dados é através do controlador.

Se, ao ler isso, você vê uma maneira de apertar o meu código, por favor comentário e deixe-me saber.

Primeiro, vamos olhar para as coisas que funcionam DO, no caso de você está preso a este, também, e precisam de ajuda.

De todas as coisas que eu tentei, a única coisa que realmente parecia trabalho foi declarar um comando after_update no Observer para o modelo. Nesse comando, eu usei o comando explícito para a ação expire_page, e incluiu um caminho que tinha sido declarada em routes.rb.

Então. Isso funciona:

Em config / routes.rb:

map.link 'l/:md5.:format',  :controller => 'links', :action => 'show'

Em app / models / link_observer.rb:

def after_update(link)
  ActionController::Base.expire_page(app.link_path(:md5 => link.md5))
end

Note que que "md5" é específico para meu aplicativo. Você pode querer usar:. ID ou algum outro identificador único

Eu também achei que declarar que ActionController :: Base ... linha a partir do método no modelo que está fazendo a atualização funcionou. Isto é, dentro Link.rb, no método que está realmente atualizar o banco de dados, se eu apenas preso a linha inteira em, funcionou. Mas desde que eu poderia querer expiram que cache de página sobre outros métodos no futuro, eu prefiro tê-lo extraídos para o Observer.

Agora, vamos olhar para algumas coisas que não funcionou, caso você esteja pesquisando por aí para isso.

Calling "expire_page (...)" dentro do método after_update (link) dentro link_observer.rb não funcionou, pois ele retornou um "undefined method` expire_page '" erro

Criação de um arquivo Sweeper que observaram o modelo não funcionou. Eu não poderia encontrar qualquer código de erro, mas apenas parecia nem mesmo estar ciente de que ele tinha um trabalho a fazer. Este foi depois de chamar explicitamente "config.load_paths + =% W (# {RAILS_ROOT} / app / Vassouras)" dentro environment.rb. Apenas no caso de eu algo de dedos de gordura nesse código, aqui está:

class LinkSweeper < ActionController::Caching::Sweeper
  observe Link

  def after_update(link)
    clear_links_cache(link)
  end

  def clear_links_cache(link)
    # DID NOT WORK    expire_page :controller => 'links', :action => 'show', :md5 => link.md5
    # DID NOT WORK    expire_page '/l/'+ link.md5 + '.html'
    # DID NOT WORK    ActionController::Base.expire_page(app.link_path(:md5 => link.md5))
  end
end

Esse exemplo acima tiveram o arquivo link_sweeper.rb em um diretório, / app / varredores. Eu também tentei colocar link_sweeper.rb dentro do diretório app / models e tentou chamá-lo com os config.active_record.observers comando no environment.rb:

config.active_record.observers = :link_observer, :link_sweeper

Mas isso não funcionou, tampouco.

Então, sim. É bem possível que um desses métodos iria funcionar, e que eu errei alguma coisa no código. Mas eu acho que fiz tudo pelo livro.

Finalmente, para resumir: Ao invés de usar uma vassoura para expirar o cache de página, você quer configurar um callback after_ no Observer do modelo. Você vai querer usar o caminho explícito para o método Base.expire_page:

def after_update(<model>) # where <model> is the name of the model you're observing
  ActionController::Base.expire_page(app.<model>_path(:id => <model>.id)) # where <model> is the name of the model you're observing
end

Esperamos que isso vai ajudar alguém no caminho. Novamente, se você ver em qualquer lugar no meu código não-trabalhando onde eu deveria ter feito algo diferente, por favor me avise. Se você ver algo no meu código de trabalho que pode ser mais apertado, por favor deixe-me saber que, também.

eu estava experimentando o mesmo problema ao tentar fazer o cache de fragmento (Rails 3). Não foi possível obter o varredor de observar, para povoada a solução para torná-lo um AR Observer como descrito acima e chamando ApplicationController.new.expire_fragment(...).

Eu fiz começar este trabalho. A única ligeira diferença na minha configuração é que o varredor é parte de um motor de Rails; que responde por pequenas diferenças (carregamento do arquivo de vassoura com um requerem no motor do init em vez de adicioná-lo ao caminho de carga em environment.rb, etc).

Assim, o varredor é carregado na init.rb do motor como este:

require File.join(File.dirname(__FILE__), 'app', 'sweepers', cached_category_count_sweeper')

I chamou-lhe uma vassoura porque "varre" o cache, mas eu acho que é apenas um observador do modelo:

class CachedCategoryCountSweeper < ActiveRecord::Observer
  observe CategoryFeature

  def before_save(cf)
    expire_cache(cf.category_id_was) if cf.category_id_changed?
  end

  def after_save(cf)
    expire_cache(cf.category_id)
  end

  def after_destroy(cf)
    expire_cache(cf.category_id)
  end

  def expire_cache(c)
    ApplicationController.expire_page("/categories/#{c}/counts.xml") if !c.nil?
  end
end

Francamente, eu não gosto de ter que codificar o caminho, mas eu tentei adicionar:

include ActionController:UrlWriter

e, em seguida, usando o método do caminho, mas só funcionou para mim no desenvolvimento. Não funcionou na produção, porque o meu servidor de produção utiliza uma raiz url relativa (em vez de hosts virtuais) e o método "page_cache_path" interna seria consistentemente obter o errado caminho do arquivo para que ele não poderia expirar.

Uma vez que este é um observador, eu adicionado ao environment.rb:

config.active_record.observers = :cached_category_count_sweeper

Finalmente, o controlador que usa o cache (não expira-lo, o que é feito através do modelo de observador):

class CachedCategoryCountsController < ApplicationController
  caches_page :index

  # GET /cached_category_counts.xml
  def index
    ...
  end
end

De qualquer forma, espero que isso ajude.

Andres Montano

Eu tenho sido capaz de obtê-lo para o trabalho, por meio de adição

ActionController::Base.expire_page(app.link_path(:md5 => @link.md5))

para o método no próprio modelo que está atualizando o banco de dados. Isto parece um pouco hacky, embora, e eu gostaria de saber se alguém pode explicar por que ele não está funcionando com a configuração normal de vassoura, e se há uma maneira mais elegante de lidar com isso.

Esse trecho de código (além de personalizações que eu ponho no para o meu próprio app) veio de este post sobre ruby-forum.com .

Eu escrevi um pouco sobre este tópico aqui: Rails cache Sweeper Confusão . Gostaria de ouvir as suas opiniões.

Com base @moiristo e respostas 's @ZoogieZork, eu estou supondo que isso iria funcionar (não testado).

class LinkSweeper < ActiveRecord::Observer
  include ActionController::Caching::Pages
  # or if you want to expire fragments
  #include ActionController::Caching::Fragments

  observe Link

  def after_update(link)
    expire_page( ... )
    #expire_fragment( ... )
  end
end
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top