Pregunta

Estoy trabajando en una aplicación Rails, donde yo estoy usando la caché de páginas para almacenar la salida HTML estático. El almacenamiento en caché funciona bien. Tengo problemas para expirar los cachés, sin embargo.

Creo que mi problema es, en parte, porque no pienso que expira el caché de mi controlador. Todas las acciones necesarias para este están siendo manejados dentro del modelo. Esta parece que debería ser factible, pero todas las referencias a la caducidad de la caché basado en modelos que yo estoy encontrando parecen estar fuera de fecha, o de otra manera no están funcionando.

En mi archivo environment.rb, llamo

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

Y tengo, en la carpeta / barredoras, un archivo 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

Así que ... qué no está borrando la página en caché cuando actualice el modelo (Proceso: el uso de la escritura / consola, estoy seleccionando los elementos de la base de datos y guardarlos, pero sus páginas correspondientes no se suprimen de la memoria caché), y también estoy llamando al método específico en el modelo de enlace que normalmente invocar la barredora. Ni las obras.

Si es importante, el archivo almacenado en caché es un hash MD5 de un valor clave en la tabla de enlaces. La página en caché se está almacenada como algo parecido a / l / 45ed4aade64d427 ... 99919cba2bd90f.html.

En esencia, parece como si la barredora en realidad no se observa el enlace. También leí ( aquí ) que podría ser posible simplemente agregar la barredora a config.active_record.observers en environment.rb, pero eso no parece hacerlo (y no estaba seguro de si el load_path de aplicación / barrenderos en environment.rb obviado eso).

¿Fue útil?

Solución

Sólo una nota:. cache_sweeper puede utilizar en 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

Otros consejos

Así que he intentado un número de diferentes enfoques, para ver lo que funciona y lo que no.

Una vez más, para resumir la situación: Mi objetivo es expirará páginas en caché cuando un actualizaciones de objetos, pero a punto de expirar sin depender de una acción del controlador barredoras convencionales utilizan una línea en el controlador de notificar. la barredora que necesita para funcionar. En este caso, no puedo usar una línea en el controlador, ya que la actualización está sucediendo dentro del modelo. tutoriales barredora normales no están funcionando, ya que presumen que su principal interacción con el objeto de base de datos es a través del controlador.

Si, al leer esto, se ve una manera de reforzar mi código, por favor, comentario y quiero saber.

En primer lugar, vamos a ver las cosas que hacen el trabajo, en caso de que usted está atascado en esto, también, y necesitan ayuda.

De todas las cosas que intenté, lo único que realmente parecía que el trabajo fue declarar un comando after_update en el Observador del modelo. En ese comando, he utilizado el comando explícito para la acción expire_page, e incluía un camino que se había declarado en routes.rb.

Así. Esto funciona:

En config / routes.rb:

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

En aplicación / modelos / link_observer.rb:

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

Tenga en cuenta que que "md5" es específico para mi aplicación. Es posible que desee utilizar:. Identificación o algún otro identificador único

También encontré que declarar que ActionController :: Base ... line a partir del método en el modelo que está haciendo la actualización funcionó. Es decir, dentro Link.rb, en el método que en realidad la actualización de la base de datos, si me quedé toda esa línea en, funcionó. Pero ya que puede ser que quiera que expirará caché de páginas de otros métodos en el futuro, prefiero que se extrae en el observador.

Ahora, vamos a ver algunas cosas que no funcionaba, en caso de que estés buscando en Google en torno a esto.

Calling "expire_page (...)" en el after_update (enlace) método dentro link_observer.rb no funcionó, ya que devuelve un "método no definido` expire_page '" error

Creación de un archivo Sweeper que se observó el modelo no funcionó. No pude encontrar los códigos de error, pero parecía que ni siquiera ser consciente de que tenía un trabajo que hacer. Esto fue después de una llamada explícita a "config.load_paths + =% W (# {} RAILS_ROOT / app / barrenderos)" dentro de environment.rb. Sólo en caso de que algo dedos de grasa en ese código, aquí 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

Eso ejemplo anterior tenía el archivo link_sweeper.rb en un directorio, / app / barrenderos. También he intentado poner link_sweeper.rb dentro del directorio app / models, y trató de llamar con los config.active_record.observers ordeno en environment.rb:

config.active_record.observers = :link_observer, :link_sweeper

Pero eso no funcionó, tampoco.

Así que, sí. Es muy posible que uno de estos métodos podría funcionar, y que en mal estado algo en el código. Pero creo que lo hice todo por el libro.

En última instancia, para resumir: En lugar de utilizar una barredora de expirar caché de páginas, desea establecer una llamada de retorno after_ con calidad de observador del modelo. Usted querrá utilizar la ruta explícita al 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 esto ayude a alguien más en el camino. Una vez más, si usted ve cualquier parte de mi código no-trabajo donde debería haber hecho algo diferente, por favor hágamelo saber. Si usted ve algo en mi código de trabajo que pueden ser más estrictos, por favor hágamelo saber eso, también.

I estaba experimentando el mismo problema cuando se trata de hacer fragmento de almacenamiento en caché (carriles 3). No se pudo obtener la barredora de observar, por lo que me conformé con la solución para que sea un observador AR como se describe anteriormente y llamando ApplicationController.new.expire_fragment(...).

Lo hice conseguir este trabajo. La única pequeña diferencia en mi configuración es que la barredora es parte de un motor de rieles; que da cuenta de las diferencias leves (carga el archivo con una barredora requerir en el motor de init en lugar de añadirlo a la ruta de carga en environment.rb, etc).

Por lo tanto, la barredora se carga en el init.rb del motor de la siguiente manera:

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

Lo he llamado un barrendero porque "barridos" la memoria caché, pero supongo que es sólo un observador en el 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, no me gusta tener que código el camino, pero he intentado añadir:

include ActionController:UrlWriter

y luego utilizando el método de la ruta, pero sólo funcionaba para mí en el desarrollo. No funcionó en la producción, porque mi servidor de producción utiliza una raíz de URL relativa (en lugar de los hosts virtuales) y el método "page_cache_path" interno obtendría constantemente la ruta del archivo mal por lo que no podría expirar.

Dado que este es un observador, añadí a la environment.rb:

config.active_record.observers = :cached_category_count_sweeper

Finalmente el controlador que utiliza la memoria caché (no expira ella, lo que se hace a través del modelo de observador):

class CachedCategoryCountsController < ApplicationController
  caches_page :index

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

En cualquier caso, espero que esta ayuda.

Andrés Montano

He sido capaz de conseguir que funcione, por medio de la adición

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

para el método en el mismo modelo que se actualiza la base de datos. Esto se siente un poco hacky, sin embargo, y me gustaría saber si alguien puede explicar por qué no está funcionando con la configuración normal barredora, y si hay una manera más elegante de manejar esto.

Ese fragmento de código (aparte de las personalizaciones que puse en mi propia aplicación) vino de este mensaje el ruby-forum.com .

he escrito un poco sobre este tema aquí: rieles caché Sweeper Confusión . Me encantaría escuchar sus opiniones.

Con base en @moiristo y @ZoogieZork 's respuestas, supongo que seguirán esto iba a funcionar (no probado).

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top