2013-07-03 17 views
27

Ho cercato di utilizzare le funzionalità di memorizzazione nella cache dei binari, ma non riesco a espirare alcuni frammenti di cache sebbene sembrino scadere. Utilizzando come sottolineato nelle rotaie sito di tutorial la 'bambola russa Caching', io sto usando questa configurazioneRails 4.0 expire_fragment/scadenza cache non funzionante

<% cache "all_available_releases" do %> 
<% @releases.each do |release| %> 
    <% cache(release) do %> 
    <html code with> 
    <%ruby code @release.name blah blah blah%> 
    <%end%> 
<%end%> 
<%end%>  

mi scadono il caching esterno nel controller release_controller.rb, dove io uso expire_fragment ("all_available_releases") per espira il frammento. Lo uso in ogni metodo del controller che aggiorna o cancella o aggiunge una voce.

Questo è il registro di WEBrick, dove sebbene il frammento di scadenza venga registrato, 5 righe dopo il frammento scaduto viene letto e utilizzato mentre non dovrebbe. Questo esempio è dopo una chiamata di distruzione.

Processing by ReleasesController#destroy as HTML 
    Parameters: {"authenticity_token"=>"***/***/********************+********=", "id"=>"2"} 
    Release Load (0.1ms) SELECT "releases".* FROM "releases" WHERE "releases"."id" = ? LIMIT 1 [["id", "2"]] 
    (0.1ms) begin transaction 
    SQL (2.0ms) DELETE FROM "releases" WHERE "releases"."id" = ? [["id", 2]] 
    (148.0ms) commit transaction 
Expire fragment views/all_available_releases (0.1ms) 
Redirected to http://127.0.0.1:3000/releases 
Completed 302 Found in 180ms (ActiveRecord: 150.2ms) 


Started GET "/releases" for 127.0.0.1 at 2013-07-03 13:09:51 +0300 
Processing by ReleasesController#index as HTML 
Read fragment views/all_available_releases/41cb0a928326986f35f41c52bb3d8352 (0.1ms) 
    Rendered releases/index.html.erb within layouts/application (0.6ms) 
Completed 200 OK in 5ms (Views: 4.0ms | ActiveRecord: 0.0ms) 

Ho anche provato ad utilizzare Rails.cache.delete("all_available_releases") e non ha funzionato neanche.

se elimino <%cache "all_available_releases"%> (e uno <%end%>) dal mio html.erb il caching funziona bene e diventa scaduto ogni volta che dovrebbe.

risposta

57

Credo che il problema è che quando si memorizzare nella cache il frammento nella vista, una cache digest viene aggiunto alla chiave di cache (viste/all_available_releases/41cb0a928326986f35f41c52bb3d8352), ma expire_fragment non utilizza il digest (viste/all_available_releases).

Se si aggiunge skip_digest: true alla chiamata della cache nella vista, si dovrebbe impedire l'utilizzo del digest.

<% cache "all_available_releases", skip_digest: true do %> 
<% @releases.each do |release| %> 
    <% cache(release) do %> 
    <html code with> 
    <%ruby code @release.name blah blah blah%> 
    <%end%> 
<%end%> 
<%end%> 

digest cache sono intesi solo per essere utilizzato con scadenza automatica della cache. Se è necessario scadere manualmente le chiavi della cache, non è possibile utilizzare i caching della cache.

+1

Questo era esattamente il mio problema, grazie. –

+0

Questo mi ha causato così tanti problemi. Grazie! – Finbarr

+2

Grazie, dove è documentato? – bonyiii

4

Jbuilder non supporta skip_digest. Dopo aver percorso molti approcci falliti, ho deciso di condividere le mie risposte in quanto è strettamente correlato, anche se non con una visualizzazione di binari come è il problema sopra.

Ecco un Q/problema correlato in cui DHH essenzialmente dice al ragazzo che non può scadere fragment_caches in modo esplicito. https://github.com/rails/cache_digests/issues/35 Tutto ciò che non è quadrato ecco un modo per aggirare questo:

class MenuController 
    def index 
    json = Rails.cache.fetch('clients') do 
     @items = Menu.all 
     render_to_string(template: 'menu/index', locals: {items: @items}) 
    end 
    render json: json 
    end 
end 

allora si può esplicitamente scade questo ovunque, come in un osservatore

class MenuCacheObserver < ActiveRecord::Observer 
    observe :menu, :menuitem, :menusubnavigation 

    def after_save obj 
    Rails.cache.delete(:clients) 
    end 
end 

In alcuni casi questo può avere senso. In generale, nella maggior parte dei casi si dovrebbe utilizzare l'oggetto nell'input della cache, ad esempio json.cache! @my_object do che avvolge la vista di jbuilder. In questo modo invaliderebbe quando update_at sull'oggetto cambia.

+0

Sembra che jbuilder supporti skip_digest ora (sto usando 2.4.0) - il seguente ha funzionato per me 'json.cache! ['v1', my_obj.cache_key], skip_digest: true, expires_in: 6.hours do json.partial! 'percorso/a/mio/parziale', obj: my_obj fine' – MaximusDominus

0

Mi sono imbattuto in questo problema e il modo in cui l'ho affrontato era attraverso le espressioni regolari. Potrebbe non essere la soluzione più elegante ma funziona bene.

ActionController::Base.new.expire_fragment(%r{offer_#{@offer.id}/*}) 

Aggiunta del skip_digest è molto più bello però.

0

In Rails 5 ho eseguito le seguenti operazioni per interrompere la cache senza ricorrere a skip_digest: true.Il nostro problema era che la modifica del valore delle stringhe I18n non si rifletteva nel digest della cache calcolato, in modo che la cache non venisse automaticamente eliminata.

Ecco la vista in cui è definito il blocco di cache:

/ views/layouts/_footer.html.slim 
- cache :footer do 
    span= t('shared.footer') 

Poi in consolle rotaie corro:

fragment = ActionController::Base.new.view_context.cache_fragment_name(:footer, virtual_path: 'layouts/_footer.html.slim') 
ActionController::Base.new.expire_fragment(fragment) 

cache_fragment_name sarà capire il digest in base all'argomento virtual_path parola chiave.