Rails 缓存分页集合

Posted

技术标签:

【中文标题】Rails 缓存分页集合【英文标题】:Rails caching a paginated collection 【发布时间】:2014-03-13 03:22:28 【问题描述】:

只是对缓存分页项目集合的最佳方法进行一些研究。目前使用jbuilder输出JSON,一直在玩各种cache_key选项。

我见过的最好的例子是使用最新记录的 updated_at 加上集合中的项目数量。

def cache_key
      pluck("COUNT(*)", "MAX(updated_at)").flatten.map(&:to_i).join("-")
end

在这里定义:https://gist.github.com/aaronjensen/6062912

但这不适用于分页项目,我的收藏中总是有 10 个项目。

有解决办法吗?

【问题讨论】:

【参考方案1】:

使用分页集合,您只会得到一个数组。任何试图修改 Array 以包含缓存键的尝试都会有点令人费解。最好的办法是使用缓存方法在集合到集合的基础上生成一个键。

您可以将很多东西传递给缓存方法来生成密钥。如果您总是每页有 10 个项目,我认为计数不是很有价值。但是,页码和最后更新的项目将是。

cache ["v1/items_list/page-#params[:page]", @items.maximum('updated_at')] do

会生成一个类似的缓存键

v1/items_list/page-3/20140124164356774568000

使用俄罗斯娃娃缓存,您还应该缓存列表中的每个项目

# index.html.erb
<%= cache ["v1/items_list/page-#params[:page]", @items.maximum('updated_at')] do %>
  <!-- v1/items_list/page-3/20140124164356774568000 -->
  <%= render @items %>
<% end %>

# _item.html.erb
<%= cache ['v1', item] do %>
  <!-- v1/items/15-20140124164356774568000 -->
  <!-- render item -->
<% end %>

【讨论】:

您还可以添加会话密钥、user_id 等并将密钥散列到摘要中。 如果中间的项目更新了怎么办? index.html.erb 中的父容器不会知道吧? 这是俄罗斯娃娃缓存的一部分。 DHH talks about it here 在#5。 嗨@JacobEvanShreve,如果该项目不属于所有内容怎么办?例如分页用户列表。 @items.max_by(&amp;:updated_at) 无论如何都会从数据库中获取项目,并且还将在 ruby​​ 中一一处理它们。我认为如果我们使用@items.maximum('updated_at') 会更好,它只会直接从数据库中获取计数。【参考方案2】:

缓存分页集合很棘手。使用集合计数和最大值updated_at 的常用技巧大多不适用!

正如你所说,收集计数是给定的,所以没有用,除非你允许动态per_page 值。

最新的updated_at 完全取决于您收藏的排序。

想象一下,添加了一条新记录并在第一页结束。这意味着一条记录,以前的第 1 页,现在进入第 2 页。以前的第 2 页记录现在变成第 3 页。如果新的第 2 页记录的更新时间不超过前一个最大值,则缓存键保持不变,但集合不是!删除记录时也会发生同样的情况。

只有当您可以保证新记录总是在最后一页结束并且永远不会删除任何记录时,使用最大值 updated_at 才是可靠的方法。

作为一种解决方案,除了页码和per page 值之外,您还可以在缓存键中包含总记录数和总最大值updated_at。这将需要额外的查询,但可能值得,具体取决于您的数据库配置和记录数。

另一种解决方案是使用考虑到实际集合内容的某种简化形式的密钥。例如,还要考虑所有记录 ID。

如果您使用 postgres 作为数据库,这个 gem 可能会对您有所帮助,尽管我自己从未使用过它。 https://github.com/cmer/scope_cache_key

还有 rails 4 前叉: https://github.com/joshblour/scope_cache_key

【讨论】:

以上是关于Rails 缓存分页集合的主要内容,如果未能解决你的问题,请参考以下文章

Java内存分页工具类

骨干.js分页

分页 Laravel 集合

Rails 3:如何汇总多个集合选择?

集合视图和详细视图分页

创建动态集合选择 rails 3.1