i collegamenti interrotti quando fanno caching dei frammenti in Rails
-
11-10-2019 - |
Domanda
Supponiamo che ci sia un blog con post, commenti e gli utenti che possono commentare. Gli utenti hanno URL SEO-friendly, come http: // localhost: 3000 / utenti / John (questo può essere fatto facilmente utilizzando permalink_fu).
Gli usi modello toccare per la memorizzazione nella cache Semplificare:
class Post
has_many :comments
end
class Comment
belongs_to :post, :touch=>true
end
E il codice vista sarebbe qualcosa di simile:
<%= cache @post do %>
<h1><%= @post.title %></h1>
<%= @post.content %>
<%= @post.comments.each do |comment| %>
<%= link_to h(comment.user), comment.user %> said:
<%= comment.content %>
<% end %>
<% end %>
Ora supponiamo John cambia il suo nick a Johnny - le sue modifiche URL a http: // localhost: 3000 / utenti / johnny. A causa di fare caching dei frammenti in post e commenti, i commenti di John punterà all'URL sbagliato Giovanni a meno che il frammento è scaduto. Può essere possibile toccare manualmente o alterarsi tutti i messaggi che contengono i commenti di John in questo esempio, ma in un'applicazione complessa ciò richiederebbe query molto complesse e sembra molto soggetto ad errori.
Qual è la migliore pratica qui? Dovrei usare URL non SEO-friendly come ad esempio / utenti / 13 invece di / utenti / John? O forse tenere un elenco di URL vecchio fino a scadenza della cache? Nessuna soluzione sembra buono per me.
EDIT: Si prega di notare che questo è solo un esempio semplificato - è sicuramente molto semplice da messaggi di interrogazione e di toccare in questo caso. Ma un'applicazione complessa implica molte relazioni tra gli oggetti che lo rende difficile da rintracciare ogni oggetto che ha un riferimento a un utente. Ho ricercato un po 'su questo -. Facebook consente solo di impostare il nome utente una volta, quindi questo problema non esiste
Soluzione
non vedo che sarebbe stato complesso per scadere i messaggi memorizzati nella cache. Impostare una spazzatrice:
class UserSweeper < ActionController::Caching::Sweeper
observe User
def after_save(user)
user.comments.collect(&:post).each do |post|
expire_fragment post
end
end
Altri suggerimenti
userei un filtro before_save ad esempio
class User
has_many :posts
before_save :touch_posts
private
def touch_posts
Post.update_all({:updated_at => Time.now}, {:user_id => self.id}) if self.login_changed?
true
end
end
Una richiesta per aggiornare il post di ogni utente. Non proprio complesso.