2

在我的 rails 4 应用程序中,我尝试使用缓存,但由于缓存键设置、缓存帮助程序和自动过期的不同版本,我有点困惑。

所以让我通过几个例子来问这个问题。我不会故意将示例移至不同的问题,因为我觉得这样任何人都可以一眼就理解细微的差异。

1:侧边栏的最新用户

我想显示最新的用户。这对于应用程序中的所有用户当然是相同的,并显示在所有页面上。在 railscasts 我看到了一个类似的例子,它通过调用expire_fragment...控制器而过期。但根据其他资源,这应该会在某些事情发生变化时自动过期(例如新用户注册)。所以我的问题是:我是否正确设置了密钥并且它会自动过期?

_sidebar.html.erb(显示在侧边栏的所有页面上)

<% cache 'latest-users' %>
  <%= render 'users/user_sidebar' %>
<% end %>

_users_sidebar.html.erb

<% @profiles_sidebar.each do |profile| %>
  <%= profile.full_name %>
  ........
<% end %>

2:产品展示页面

我想展示给定的产品(仅在展示页面上)。这对所有用户来说都是一样的,但是因为有更多的产品,所以有更多的版本。问题又是一样的:我是否正确设置了密钥,它会自动过期吗?

产品/show.html.erb

<% cache @product %>
  <%= @product.name.upcase %>
  <%= @product.user.full_name %>
<% end %>

3:产品/索引(用 will-paginate gem 分页)

在这里,我想一次缓存分页给定页面上的所有产品,因此产品被缓存在块中。这对所有用户也是一样的,并且只会显示在products index page. (稍后我想russian-doll-caching在此页面上为单个产品实施。)我的问题:我这样做是否正确,它会自动过期吗?

产品 index.html.erb

<% cache [@products, params[:page]] %>
  <%= render @products %>
<% end %>

_product.html.erb

<%= product.name %>
<%= product.user.full_name %>
.....

我尝试使用的示例代码(不确定它是否好用):

首先是索引页,没有俄罗斯娃娃。

在此处输入图像描述

其次是带有评论的展示页面的俄罗斯娃娃。

在此处输入图像描述

4

2 回答 2

2

恕我直言,缓存键是整个概念的精神。

现在让我们讨论这些例子。

  1. 侧边栏中的最新用户:将字符串固定为缓存键

cache_key可能是views/latest-users/7a1156131a6928cb0026877f8b749ac9摘要7a11561..是缓存块文字的 MD5。

在这种情况下,缓存仅在您更改模板或此块中的任何内容时才会过期。

<% cache 'latest-users' do %>
  <%= render 'users/user_sidebar' %>
<% end %>
  1. 产品展示页面:对象作为缓存键

cache_key可能是views/product/123-20160330214154/9be3eace37fa886b0816f107b581ed67,请注意缓存是带有#{product.to_s}/ #{product.id}-的命名空间#{product.updated_at}

product.updated_at在这种情况下,缓存在 (1)更改或 (2) 缓存块字面量更改时过期。

并注意缓存与不同的产品不同id

<% cache @product %>
  <%= @product.name.upcase %>
  <%= @product.user.full_name %>
<% end %>
  1. 产品/索引(使用 will-paginate gem 分页):数组作为缓存键

cache_key不能views/product/123-20160330214154/product/456-20160330214154/d5f56b3fdb0dbaf184cc7ff72208195e确定这一点。但无论如何,它应该是这样扩展的。

在这种情况下,缓存在 (1) product-123 或 product-456 更改(已product.updated_at更改)或 (2) 缓存块字面量更改时过期。

@products并且缓存的内容因它们的不同而不同ids,所以不需要追加params[:page],因为它们的内容不同,它会缓存每个不同的页面@products

<% cache [@products, params[:page]] %>
  <%= render @products %>
<% end %>

你可以阅读 DHH 写的文章,它很好地描述了俄罗斯娃娃缓存。和API 文档

于 2016-03-30T15:32:57.610 回答
2

缓存单个记录和记录集合之间有很大的区别。

通过查看时间戳,您可以非常简单地判断一条记录是否已更改。默认的 cache_key 方法是这样工作的:

Product.new.cache_key     # => "products/new" - never expires
Product.find(5).cache_key # => "products/5" (updated_at not available)
Person.find(5).cache_key  # => "people/5-20071224150000" (updated_at available)

然而,判断一个集合何时过时在很大程度上取决于它的使用方式。

在您的第一个示例中,您只真正关心created_at时间戳 - 在其他情况下,您可能希望查看记录何时更新,甚至何时插入/更新相关记录。这里没有正确的答案。

1.

首先,您将拉出按以下顺序排列的 N 个用户created_at

@noobs = User.order(created_at: :desc).limit(10)

我们可以通过查看集合中的第一个用户来简单地使缓存失效。

<!-- _sidebar.html.erb -->
<% cache(@noobs.first) do %>
  <%= render partial: 'users/profile', collection: @noobs %>
<% end %>

我们可以这样做,因为我们知道如果一个新用户注册了,他会将之前的第一名推到一个位置。

然后我们可以使用俄罗斯娃娃缓存来缓存每个单独的用户。请注意,由于调用profile了局部变量,因此局部变量被传递profile

<!-- users/_profile.html.erb -->
<% cache(profile) do %>
  <%= profile.full_name %>
<% end %>

2.

是的。它将过期。您可能希望像其他示例一样部分使用俄罗斯娃娃缓存。

3.

对于分页集合,您可以使用数组中记录的 id 来创建缓存键。

已编辑。

由于您不希望提供可能更新的产品的陈旧表示,因此您还希望updated_at在俄罗斯娃娃的“外层”中用作缓存键。

在这种情况下,完全加载记录是有意义的。你可以忽略我之前关于.ids.

产品/index.html.erb:

<% cache([@products.map(&:id), @products.map(&:updated_at).max]) do %>
  <%= render @products %>
<% end %>

产品/_product.html.erb:

<% cache(product) do %>
  <%= product.name %>
<% end %>
于 2016-03-30T15:40:50.977 回答