ruby-on-rails - Rails 3 和 Memcached - 智能缓存,永不过期

标签 ruby-on-rails ruby caching memcached cache-expiration

我正在通过 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/

相关文章:

ruby-on-rails - 如何从 RSpec 中的 Controller 调用创建操作

ruby-on-rails - 在 before_action 中访问 application_helper

java - 根据某些配置参数从代码中禁用缓存抽象

caching - 用于 Redis 缓存和 TTL 的 ASP.NET session 状态提供程序

c++ - 在写入高带宽数据流时如何最好地管理 Linux 的缓冲行为?

ruby-on-rails - 如何使用 activerecord 和 POSTGRES 平均产品评论分数

ruby-on-rails - 如何为 ToyStore 模型构建观察者?

ruby-on-rails - 我缺少迁移文件

regex - 使用 scan 方法 + regexp 将字符串分解为单词,如果单词有 `' ` 字符,则删除该字符及其后的所有内容

ruby-on-rails - 在 127.0.0.1:6379 上连接到 Redis 时出错 (Errno::ECONNREFUSED) - Wercker