Question

Je travaille sur une application Rails, où je suis en utilisant la mise en cache de la page pour stocker la sortie html statique. La mise en cache fonctionne très bien. Je ne parviens pas à les caches venant à échéance, cependant.

Je crois que mon problème est, en partie, parce que je ne suis pas expirant le cache de mon contrôleur. Toutes les mesures nécessaires à cet effet sont en cours de traitement au sein du modèle. Cela semble que cela devrait être faisable, mais toutes les références à l'expiration du cache à base de modèle que je trouve semblent être à jour, ou sont autrement ne fonctionne pas.

Dans mon fichier environment.rb, j'appelle

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

Et j'ai, dans le dossier / balayeuses, un fichier 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

... pourquoi pas supprime la page en cache lorsque je mets à jour le modèle (processus: je sélectionne les éléments de la base de données et de les enregistrer en utilisant un script / console, mais leurs pages correspondantes ne sont pas supprimer du cache), et j'appelle aussi la méthode spécifique dans le modèle de lien qui invoquerait normalement la balayeuse. Ni les œuvres.

S'il importe, le fichier cache est un hachage md5 hors une valeur clé dans la table Liens. La page en cache est stocké se quelque chose comme / l / 45ed4aade64d427 ... 99919cba2bd90f.html.

Pour l'essentiel, il semble que la balayeuse ne respecte pas fait le lien. Je lis aussi ( ) qu'il pourrait être possible d'ajouter simplement la balayeuse à config.active_record.observers dans environment.rb, mais cela ne semble pas le faire (et je ne sais pas si l'load_path d'app / balayeuses dans environment.rb que obvié).

Était-ce utile?

La solution

Juste une note:. Vous pouvez utiliser cache_sweeper dans 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

Autres conseils

Je l'ai essayé un certain nombre d'approches différentes, pour voir ce qui fonctionne et ce qui ne fonctionne pas.

Encore une fois, pour résumer la situation: Mon but est d'expirer les pages mises en cache lorsqu'une mise à jour de l'objet, mais les expireront sans compter sur une action de contrôleur balayeuses conventionnelles utilisent une ligne dans le contrôleur de notification. la balayeuse dont il a besoin pour fonctionner. Dans ce cas, je ne peux pas utiliser une ligne dans le contrôleur, comme la mise à jour se produit dans le modèle. tutoriels balayeuse normaux ne fonctionnent pas, car ils présument que votre interaction principale avec l'objet de base de données est par le contrôleur.

Si, en lisant cela, vous voyez un moyen de resserrer mon code, s'il vous plaît commentaire et laissez-moi savoir.

Tout d'abord, regardons les choses qui fonctionnent, dans le cas où vous êtes coincé sur ce point, aussi, et ont besoin d'aide.

De toutes les choses que j'ai essayé, la seule chose qui semblait vraiment le travail était de déclarer une commande after_update dans l'Observateur du modèle. Dans cette commande, je la commande explicite pour l'action expire_page, et un chemin qui inclus avait été déclarée routes.rb.

. Cela fonctionne:

Dans config / routes.rb:

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

app / modèles / link_observer.rb:

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

Notez que ce « md5 » est spécifique à mon application. Vous pouvez utiliser: id. Ou un autre identifiant unique

Je trouve aussi que déclarant que ActionController :: Base ... ligne de la méthode dans le modèle qui fait la mise à jour a fonctionné. C'est, dans Link.rb, dans la méthode qui est mise à jour en fait la base de données, si je viens coincé cette ligne tout en, cela a fonctionné. Mais depuis que je pourrais vouloir expirer que le cache de page sur d'autres méthodes à l'avenir, je préférerais l'avez extrait dans l'observateur.

Maintenant, regardons certaines choses qui ne marchait pas, dans le cas où vous googler autour pour cela.

Appel "expire_page (...)" dans la méthode after_update (lien) dans link_observer.rb ne fonctionne pas, car il a renvoyé une erreur "méthode non définie expire_page '"

Création d'un fichier Sweeper qui a observé le modèle ne fonctionne pas. Je ne pouvais pas trouver un code d'erreur, mais ça ne semblait même pas être au courant qu'il avait un travail à faire. Ce fut après avoir appelé explicitement "config.load_paths + =% W (# {RAILS_ROOT} / app / balayeuses)" dans les environment.rb. Juste au cas où quelque chose que je graisse dans ce code doigter, ici il 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

Ce exemple ci-dessus avait le fichier link_sweeper.rb dans un répertoire, / app / balayeuses. J'ai aussi essayé de mettre link_sweeper.rb dans le répertoire app / modèles, et essayé d'appeler avec la commande config.active_record.observers dans environment.rb:

config.active_record.observers = :link_observer, :link_sweeper

Mais cela ne fonctionne pas non plus.

Alors, oui. Il est tout à fait possible que l'une de ces méthodes fonctionnerait, et que je foiré quelque chose dans le code. Mais je pense que je l'ai fait tout par le livre.

En fin de compte, pour résumer: Plutôt que d'utiliser un Sweeper expirer la mise en cache de page, vous voulez mettre en place un rappel after_ dans L'Observateur du modèle. Vous voulez utiliser le chemin d'accès explicite à la méthode 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

Espérons que cela vous aidera quelqu'un d'autre sur la route. Encore une fois, si vous voyez partout dans mon code sans travail où je aurais dû faire quelque chose différemment, s'il vous plaît laissez-moi savoir. Si vous voyez quelque chose dans mon code de travail qui peut être plus serré, s'il vous plaît me faire savoir que, aussi.

Je ressentais le même problème en essayant de faire la mise en cache des fragments (rails 3). Impossible d'obtenir la balayeuse d'observer, donc je me suis installé pour la solution pour en faire un observateur AR comme décrit ci-dessus et appelant ApplicationController.new.expire_fragment(...).

Je l'ai fait obtenir ce travail. La seule légère différence dans ma configuration est que la balayeuse fait partie d'un moteur Rails; qui représente de légères différences (chargement du fichier balayeuse avec un besoin dans la place du moteur init ajouter au chemin de charge dans environment.rb, etc).

Ainsi, la balayeuse est chargé dans le init.rb du moteur comme ceci:

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

Je l'ai appelé une balayeuse parce qu'il « balaye » le cache, mais je suppose que son juste un observateur sur le modèle:

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

Franchement, je n'aime pas avoir à coder en dur le chemin, mais j'ai essayé d'ajouter:

include ActionController:UrlWriter

et puis en utilisant la méthode du chemin, mais il ne fonctionnait pour moi dans le développement. Il n'a pas fonctionné dans la production, parce que mon serveur de production utilise une racine URL relative (au lieu des hôtes virtuels) et la méthode interne « page_cache_path » serait toujours obtenir le chemin du fichier mal donc il ne pouvait pas expirer.

Puisque c'est un observateur, j'ai ajouté à la environment.rb:

config.active_record.observers = :cached_category_count_sweeper

Enfin, le contrôleur qui utilise le cache (n'expire pas, cela se fait par l'observateur du modèle):

class CachedCategoryCountsController < ApplicationController
  caches_page :index

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

Quoi qu'il en soit, espérons que cette aide.

Andres Montano

Je suis en mesure de le faire fonctionner, par l'ajout

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

à la méthode dans le modèle lui-même qui est mise à jour la base de données. Cela se sent un peu hacky, cependant, et j'aimerais savoir si quelqu'un peut expliquer pourquoi il ne fonctionne pas avec la configuration normale de la balayeuse, et s'il y a une façon plus élégante de gérer cela.

Ce bout de code (en dehors de personnalisations que je mets dans ma propre application) est venu de ce post sur ruby-forum.com .

J'ai écrit un peu sur ce sujet ici: Rails Cache Confusion Sweeper . Aimerait entendre vos opinions.

Sur la base des réponses de l » @moiristo et @ZoogieZork, je devine que cela fonctionnerait (non testé).

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top