【问题标题】:rails 4 fragment caching for different viewsrails 4片段缓存用于不同的视图
【发布时间】:2016-07-18 11:18:10
【问题描述】:

在我的 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 %>
.....

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

第一个有索引页,没有俄罗斯娃娃。

第二个是俄罗斯娃娃与cmets的展示页面。

【问题讨论】:

  • 如果你没有读到这一行:你可以阅读 DHH 写的article,它很好地描述了俄罗斯娃娃缓存。还有API doc
  • 感谢 abookyun!我以前读过这篇文章,但不太喜欢这篇文章,因为它使用的是 rails3 语法,在这种语法中你必须使用“v1”、“v5”等。如果你是这个主题的新手,这有点令人困惑。我会查看 api 文档。

标签: ruby-on-rails caching memcached fragment-caching russian-doll-caching


【解决方案1】:

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

您可以很简单地通过查看时间戳来判断单个记录是否已更改。默认的 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 作为俄罗斯娃娃“外层”中的缓存键。

在这种情况下,完全加载记录是有意义的。你可以忽略我之前关于.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 %>

【讨论】:

  • max,很好解释。由于我缺乏经验,我有一些问题。在 2. 示例的情况下,我如何使用 russian-doll-caching?页面上只有 1 条记录。我的其他 2 个问题是关于 mapids 的:如果加载数据,map 会更快吗?据我所知,分页的重点是不应该加载数据。那么这种情况下如何加载数据呢?
  • 抱歉,我把 2 中的示例与 3 完全混淆了。当您只呈现一条记录时,russian-doll-caching 并不是很相关。
  • 3.如果您在其他任何地方使用该集合,它可能已经被加载。但是,我刚刚意识到,如果您不提供过时的版本,您可能还想使用 updated_at 作为密钥。已编辑。
  • max,我对缓存完全陌生。抱歉,但我看不到您使用 updated_at 编辑答案的位置。我还用我认为与您的答案不同的示例更新了我的问题。
  • max,如果您不介意,我还有最后一个问题:为什么我不能在 1. 示例中简单地使用 &lt;% cache 'sidebar_users' %&gt;。是因为可选的俄罗斯娃娃吗?
【解决方案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} 的命名空间。

在这种情况下,缓存在 (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) 产品 123 或产品 456 更改(product.updated_at 更改)或 (2) 缓存块字面量更改时过期。

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

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

你可以阅读 DHH 写的article,它很好地描述了俄罗斯娃娃缓存。还有API doc

【讨论】:

    猜你喜欢
    • 2014-12-23
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 2019-12-23
    • 2016-11-18
    • 2012-07-02
    • 2012-10-22
    • 2015-05-31
    相关资源
    最近更新 更多