2012-12-03 8 views
6

Ho una pagina iniziale con alcuni partial resi in tutta la pagina. Inoltre ha anche l'intestazione di sessione (login). parziale contiene set di libri impaginati. Ora voglio mettere in cache questo parziale in quanto viene aggiornato una volta alla settimana.Memorizzazione nella cache di particolari binari parziali 3.0.x

  • Domanda 1: Come si memorizza in cache quel particolare parziale (senza battere db)?
  • Domanda 2: Come si elimina (scadono) i contenuti memorizzati nella cache quando aggiornamento del modello di libri?

risposta

8

Stai cercando fragment caching qui, che si verifica sul livello vista. Il caching dei frammenti e la scadenza dei contenuti memorizzati è sorprendentemente facile da fare. Si dispone di un elenco di libri, quindi diciamo che il vostro vista sembra un po 'come questo:

<ul> 
    <% @books.each do |book| %> 
    <li><%= book.name %></li> 
    <% end %> 
</ul> 

Per abilitare il caching proprio per questo po', basta avvolgerlo in cache:

<% cache do %> 
    <ul> 
    <% @books.each do |book| %> 
     <li><%= book.name %></li> 
    <% end %> 
    </ul> 
<% end %> 

Naturalmente, questo non nomina il cache o fa qualcosa di veramente speciale con esso ... mentre Rails selezionerà automaticamente un nome univoco per questo frammento di cache, non sarà molto utile. Possiamo fare di meglio Usiamo la tecnica key-based cache expiration di DHH e forniamo alla cache un nome relativo al suo contenuto.

<% cache ['book-list', *@books] do %> 
    <ul> 
    <% @books.each do |book| %> 
     <li><%= book.name %></li> 
    <% end %> 
    </ul> 
<% end %> 

Passare argomenti nella cache crea la chiave di cache dagli argomenti forniti. Le stringhe vengono passate direttamente - quindi, qui, la cache sarà sempre preceduta da 'book-list'. Questo serve a prevenire collisioni nella cache con altri luoghi in cui è possibile memorizzare nella cache lo stesso contenuto, ma con una vista diversa. Per ogni membro dell'array @books, Rails chiamerà cache_key: per gli oggetti ActiveRecord, questo produce una stringa composta dal suo modello, ID e, in modo cruciale, l'ultima volta che l'oggetto è stato aggiornato.

Ciò significa che quando si aggiorna l'oggetto, la chiave di cache per questo frammento cambierà. In altre parole, è automaticamente scaduto: quando un libro viene aggiornato, questa istruzione cache cerca una chiave inesistente, conclude che non esiste e la popola con nuovi contenuti. I contenuti vecchi e obsoleti rimarranno nel tuo archivio cache fino a quando non saranno sfrattati dalla memoria o dai limiti di età (memcached lo fa automaticamente).

Uso questa tecnica in numerose applicazioni di produzione e funziona meravigliosamente. Per ulteriori informazioni, controllare che 37signals post e per informazioni generali sulla memorizzazione nella cache in Rails, vedere Ruby on Rails caching guide.

+0

+1 sul Splatting collezione @books. Non avrei mai pensato a questo, di solito prendevo il record del libro aggiornato più recentemente nell'intero tavolo e lo usavo. – cpuguy83

+0

Dovresti anche mettere in cache ogni singolo libro in modo che un libro modificato non interrompa l'intera cache. – cpuguy83

4

"Ci sono solo due problemi difficili in Informatica: invalidazione della cache e denominazione delle cose."
- Phil Karlton

Caching


Il Rails Guide to caching è probabilmente sempre un buon punto di ingresso per il costruito nel strategie di caching rotaie ha da offrire.In ogni caso ecco che arriva il mio approccio molto facile da caching

# _partial.html.erb 
<% cache(some_key, :expires_in => 1.week) do %> 
    <%# ... content %> 
<% end %> 

Ora alcuni some_key può essere qualsiasi stringa fintanto che è unico. Ma di nuovo cerchiamo di essere un po 'più intelligenti e rendere la chiave in qualche modo dipendente dall'elenco dei libri. Supponiamo che in realtà passi nell'array di books alcune query restituite quindi chiamate su rotaia su ciascuna delle sue voci e infine costruisca una chiave univoca per questa raccolta. Quindi, quando la raccolta cambia i cambiamenti chiave. Questo perché è implementato in ActiveRecord::Base e quindi disponibile su tutti i modelli. E ancora di più utilizza anche i timestamp, se disponibili.

Ma poi di nuovo questo colpirà il db ogni volta che viene effettuata una richiesta. Lo stesso in codice:

# controller_method 
@weekly_books = Books.where 'condition' 

# _partial.html.erb 
<% cache(@weekly_books) do %> 
    <%# ... content %> 
<% end %> 

per evitare di colpire il db a volte si può anche memorizzare nella cache la query sua auto avvolgendo la chiamata:

# Book.rb 
def self.weeklies 
    Rails.cache.fetch("book_weeklies", :expires_in => 1.day) do 
    Books.where 'condition' 
    end 
end 

# controller_method 
@weekly_books = Books.weeklies 

# _partial.html.erb 
<% cache(@weekly_books) do %> 
    <%# ... content %> 
<% end %> 
+0

Il problema è nella mia home page I libri sono impaginati. Invio i libri impaginati a partial. Ora se uso Books.weeklies, questo non darà record impaginati. Come raggiungerlo? –

Problemi correlati