rails 4片段缓存不同的视图

时间:2016-03-30 12:36:31

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

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

因此,让我通过几个例子来问这个问题。我不会故意将这些例子移到不同的问题上,因为我觉得这样一来任何人都可以一眼就看出细微的差异。

1:侧栏中的最新用户

我想显示最新用户。这当然对应用程序中的所有用户都是相同的,并显示在所有页面上。在railscast中,我看到了一个类似的例子,它通过在控制器中调用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:产品展示页

我想要显示给定的产品(仅在展会页面上)。对于所有用户来说,这是相同的,但是由于有更多产品,因此有更多版本。问题再次相同:我是否正确设置密钥并自动过期?

products / 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 %>
.....

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

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

enter image description here

其次是带有评论的节目页面的俄罗斯娃娃。

enter image description here

2 个答案:

答案 0 :(得分:2)

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

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

  1. 侧栏中的最新用户:固定字符串作为缓存键
  2. cache_key可以是views/latest-users/7a1156131a6928cb0026877f8b749ac9,摘要7a11561..是缓存块文字的MD5。

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

    <% cache 'latest-users' do %>
      <%= render 'users/user_sidebar' %>
    <% end %>
    
    1. 产品展示页面:对象作为缓存密钥
    2. 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分页):array as cache key
      2. cache_key可能views/product/123-20160330214154/product/456-20160330214154/d5f56b3fdb0dbaf184cc7ff72208195e对此不确定。但无论如何,应该扩展这样的东西。

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

        缓存与@products的{​​{1}}的不同内容不同,因此无需附加ids,因为它们不同,它会缓存每个不同的页面params[:page]内容。

        @products

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

答案 1 :(得分: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。

首先,您将提取按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 %>

我们可以这样做,因为我们知道如果注册了一个新用户,他会将前一个号码撞到一个位置。

然后我们可以使用俄语玩偶缓存来缓存每个用户。请注意,由于partial被称为profile,因此partial传递了局部变量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 %>