6

我有一个主页,它在整个页面上呈现了一些部分。它也有会话标题(登录)。部分包含分页的书籍集。现在我想缓存这个部分,因为它每周更新一次。

  • 问题 1:如何缓存特定的部分(不打 db)?
  • 问题 2:当我更新图书模型时,如何删除(过期)缓存内容?
4

2 回答 2

8

您在这里寻找片段缓存,它发生在视图层上。片段缓存和存储内容的过期非常容易做到。你有一个书籍清单,所以假设你的视图看起来有点像这样:

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

要为这一位启用缓存,只需将其包装在cache

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

当然,这并没有为缓存命名或对它做任何特别的事情……虽然 Rails 会为这个缓存片段自动选择一个唯一的名称,但它并没有真正的帮助。我们可以做得更好。让我们使用 DHH 的基于键的缓存过期技术,并给缓存一个与其内容相关的名称。

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

将参数传递到缓存中会根据提供的参数构建缓存键。字符串是直接传入的——所以,在这里,缓存总是以“book-list”开头。这是为了防止与您可能​​正在缓存相同内容但具有不同视图的其他地方发生缓存冲突。对于@books 数组的每个成员,Rails 将调用cache_key: 对于 ActiveRecord 对象,这会产生一个由其模型、ID 以及最重要的是对象上次更新时间组成的字符串。

这意味着当你更新对象时,这个片段的缓存键将会改变。换句话说,它会自动过期——当一本书更新时,这个缓存语句将搜索一个不存在的键,断定它不存在,并用新的内容填充它。旧的、陈旧的内容将在您的缓存存储中徘徊,直到被内存或年龄限制驱逐(memcached 会自动执行此操作)。

我在许多生产应用程序中使用了这种技术,并且效果很好。有关更多信息,请查看37signals 帖子,有关 Rails 中的一般缓存信息,请参阅Ruby on Rails 缓存指南

于 2012-12-03T18:22:10.510 回答
4

“计算机科学只有两个难题:缓存失效和命名事物。”
——菲尔·卡尔顿

缓存


Rails 缓存指南可能始终是Rails必须提供的内置缓存策略的一个很好的切入点。无论如何,这是我非常简单的缓存方法

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

现在 somesome_key可以是任何字符串,只要它是唯一的。但话又说回来,让我们尝试更聪明一点,让密钥以某种方式依赖于书籍列表。假设您实际上传入了books一些返回的查询数组,然后 rails 调用cache_key它的每个条目并最终为该集合构造一个唯一键。因此,当集合更改时,键会更改。那是因为在所有模型cache_key中实现ActiveRecord::Base并因此可用。而且,如果可用,它甚至会使用时间戳。

但话又说回来,每次发出请求时,这都会击中数据库。代码相同:

# controller_method
@weekly_books = Books.where 'condition'

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

为了避免经常访问数据库,您还可以通过包装调用来缓存查询本身:

# 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 %>
于 2012-12-03T18:32:42.863 回答