我一直在尝试使用rails的缓存功能,但我无法使某些缓存片段过期,尽管它们似乎已过期。使用rails教程网站中指出的'俄罗斯娃娃缓存',我正在使用此配置
<% 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%>
我在release_controller.rb控制器中使外部缓存失效,我使用expire_fragment(“all_available_releases”)来使片段过期。我在控制器的每个更新或删除或添加条目的方法中使用它。
这是WEBrick的日志,虽然expire片段已经注册,但5行之后读取并使用过期片段,而不应该。此示例是在销毁调用之后。
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)
我甚至尝试使用Rails.cache.delete("all_available_releases")
,但它也无效。
如果我从html.erb中删除<%cache "all_available_releases"%>
(以及一个<%end%>
),则缓存可以正常工作,并且只要它应该到期就会过期。
答案 0 :(得分:60)
我认为问题是当你在视图中缓存片段时,缓存摘要被添加到缓存键(views / all_available_releases / 41cb0a928326986f35f41c52bb3d8352 ),但是expire_fragment没有使用摘要(视图/ all_available_releases)。
如果在视图中向缓存调用添加skip_digest: true
,则应阻止使用摘要。
<% 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%>
缓存摘要仅用于自动缓存过期。如果您需要手动使缓存密钥到期,则无法使用缓存摘要。
答案 1 :(得分:4)
Jbuilder不支持skip_digest。在经历了许多失败的方法之后,我决定在这里分享我的答案,因为它与高度相关,尽管不是像上面的问题那样使用rails视图。
这是一个相关的问题/问题,DHH基本上告诉那个人他不能明确地使fragment_caches失效。 https://github.com/rails/cache_digests/issues/35 一切都不是正方形所以这是一个方法:
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
那么你可以在任何地方明确地过期,就像在观察者中一样
class MenuCacheObserver < ActiveRecord::Observer
observe :menu, :menuitem, :menusubnavigation
def after_save obj
Rails.cache.delete(:clients)
end
end
在少数情况下,这可能有意义。一般来说,在大多数情况下,您应该使用缓存输入中的对象,例如json.cache! @my_object do
包装jbuilder视图。这样,当对象上的updated_at发生变化时,它将无效。
答案 2 :(得分:0)
我自己遇到了这个问题,我处理它的方式是通过正则表达式。它可能不是最优雅的解决方案,但它工作正常。
ActionController::Base.new.expire_fragment(%r{offer_#{@offer.id}/*})
尽管添加skip_digest要好得多。
答案 3 :(得分:0)
在Rails 5中,我采取了以下步骤来破解缓存而不诉诸skip_digest: true
。我们的问题是更改I18n字符串的值并不反映在计算的缓存摘要中,因此缓存不会自动被破坏。
以下是定义缓存块的视图:
/ views/layouts/_footer.html.slim
- cache :footer do
span= t('shared.footer')
然后在rails控制台中运行:
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
会根据virtual_path
关键字参数找出摘要。