我正在通过 Memcached 在我的 Rails 项目中实现缓存,特别是尝试缓存侧列 block (最新的照片、博客等),目前我让它们每 15 分钟左右使缓存过期。这可行,但如果我可以做到更新,比如每当添加、更新新内容或诸如此类的时候,那就更好了。
我正在观看 Memcached 上的 Scaling Rails 截屏视频 http://content.newrelic.com/railslab/videos/08-ScalingRails-Memcached-fixed.mp4 ,在视频的 8:27 处,Gregg Pollack 谈论了 Memcached 中的智能缓存,其中智能 key (在本例中为 update_at 时间戳)用于替换以前缓存的项目,而不必使缓存过期。因此,我认为,每当更新时间戳时,缓存都会刷新,因为它会寻求新的时间戳。
在此示例中,我使用“最近的照片”侧栏,这就是它的设置方式...
_side-column.html.erb:
<div id="photos"">
<p class="header">Photos</p>
<%= render :partial => 'shared/photos', :collection => @recent_photos %>
</div>
_photos.html.erb
<% cache(photos) do %>
<div class="row">
<%= image_tag photos.thumbnail.url(:thumb) %>
<h3><%= link_to photos.title, photos %></h3>
<p><%= photos.photos_count %> Photos</p>
</div>
</div>
<%结束%>
第一次运行时,Memcached 将该 block 缓存为views/photos/1-20110308040600,并在页面刷新时重新加载缓存的片段,到目前为止一切顺利。然后,我将额外的照片添加到后端的该特定行并重新加载,但照片计数未更新。日志显示它仍在从views/photos/1-20110308040600加载并且没有获取更新的时间戳。我所做的一切似乎都与视频中所做的相同,我上面做错了什么?
此外,这个问题还有第二部分。正如您在上面的部分中看到的,为集合调用 @recent_photos 查询(在我的 lib 文件夹中的模块之外)。然而,我注意到即使该 block 被缓存,这个 SELECT 查询仍然被调用。我首先尝试将整个部分包装在一个 block 中,如 <% cache(@recent_photos) do %> ,但显然这不起作用 - 特别是因为整个集合上没有真正的时间戳,当然它只是单个项目。如果结果已缓存,如何防止进行此查询?
更新 在引用第二个问题时,我发现除非Rails.cache.exist?可能只是我的票,但棘手的是使用时间戳的通配符性质......
更新2 完全忽略我的第一个问题,我确切地弄清楚了缓存不刷新的原因。那是因为 Updated_at 字段没有被更新。原因是我要添加/删除一个项目,该项目是父级中的嵌套资源,并且我可能需要对其实现“触摸”,以便更新父级中的 Updated_at 字段。
但是我的第二个问题仍然存在......即使片段被缓存,主要的@recent_photos查询仍然被调用......有没有办法使用cache.exists?定位名为/views/photos/1-2011random 之类的缓存?
最佳答案
Rails 缓存的主要缺陷之一是您无法可靠地将缓存组件的 Controller 和 View 分开。我发现的唯一解决方案是直接将查询嵌入到缓存 block 中,但最好通过辅助方法。
例如,您可能有这样的事情:
class PhotosController < ApplicationController
def index
# ...
@recent_photos = Photos.where(...).all
# ...
end
end
第一直觉是仅在 View 需要时才运行该查询,例如测试缓存内容是否存在。不幸的是,内容有可能会在您测试缓存和实际渲染页面之间的时间间隔内过期,这会在 nil 值 @recent_photos
时导致模板渲染错误已使用。
这是一个更简单的方法:
<%= render :partial => 'shared/photos', :collection => recent_photos %>
不使用实例变量,而是使用辅助方法。定义您的辅助方法,因为您将在 Controller 内加载:
module PhotosHelper
def recent_photos
@recent_photos ||= Photos.where(...).all
end
end
在这种情况下,会保存该值,以便对同一帮助器方法的多次调用只会触发一次查询。这在您的应用程序中可能不是必需的,可以省略。毕竟,该方法必须做的就是返回“最近照片”列表。
如果 Rails 支持子 Controller 及其自己的关联 View (这是此处使用的模式的变体),则可以消除很多困惑。
关于ruby-on-rails - Rails 3 和 Memcached - 智能缓存,永不过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5598136/