rails 4个不同视图的片段缓存

rails 4 fragment caching for different views

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

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

1: 侧边栏中的最新用户

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

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

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

_用户_sidebar.html.erb

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

2:产品展示页面

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

products/show.html.erb

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

3:products/index(使用 will-paginate gem 分页)

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

产品索引。html.erb

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

_product.html.erb

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

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

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

第二个是带有评论的展示页面的俄罗斯娃娃。

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

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

  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}.

的命名空间

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

注意缓存与不同产品的区别 id

<% cache @product %>
  <%= @product.name.upcase %>
  <%= @product.user.full_name %>
<% end %>
  1. products/index(使用 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 %>

您可以阅读 article written by DHH, it described Russian Doll Caching very well. And the API doc

缓存单个记录和缓存记录集合之间存在很大差异。

您可以通过查看时间戳非常简单地判断单个记录是否已更改。默认的 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.

首先,您将拉取按 created_at:

排序的 N 个用户
@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 作为俄罗斯套娃 "outer layer" 中的缓存键。

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

的评论

products/index.html.erb:

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

products/_product.html.erb:

<% cache(product) do %>
  <%= product.name %>
<% end %>