【问题标题】:Why does this cache statement not write the key I expect?为什么这个缓存语句没有写出我期望的键?
【发布时间】:2017-05-03 10:36:57
【问题描述】:

我的 _profile.html.erb 部分中有这个:

<% cache [current_user.roles.first, profile, @selected_profile, params[:rating]] do %>

但这是我在服务器日志中看到的:

Read fragment views/profiles/26-20161212033839290582/profiles/52-20161213010040474070/profiles/14-20161213015458288839/profiles/34-20161212035644491093/profiles/33-20161212035644237925/profiles/38-20161207092843851446/profiles/35-20161212040016291016/profiles/36-20161212040016565707/profiles/4-20161213021028862933/profiles/39-20161207092843925084/profiles/46-20161207092844067579/profiles/47-20161207223703646028/profiles/37-20161212040016656625/660bdc6ad0b20e4c5329112cf79946f7 (0.1ms)

我在那里没有看到关于roles 的任何信息。

发生的情况是,如果我以具有 admin 角色的用户身份登录,然后以具有另一个角色的用户身份登录,我会看到缓存的 profiles 显示为好像我是管理员而不是与其他具有正确视图的用户一样。

这可能是什么原因造成的,我该如何解决?

编辑 1

如果我将cache 语句更改为:

<% cache [current_user, profile, @selected_profile, params[:rating]] do %>

刷新一下,日志是这样的:

Write fragment views/users/2-20161218005548388099/profiles/37-20161212040016656625///bb163edd4a8c7af2db71a04243338e7b (0.1ms)
  Rendered collection of profiles/_profile.html.erb [1 times] (25.4ms)
Write fragment views/profiles/26-20161212033839290582/profiles/52-20161213010040474070/profiles/14-20161213015458288839/profiles/34-20161212035644491093/profiles/33-20161212035644237925/profiles/38-20161207092843851446/profiles/35-20161212040016291016/profiles/36-20161212040016565707/profiles/4-20161213021028862933/profiles/39-20161207092843925084/profiles/46-20161207092844067579/profiles/47-20161207223703646028/profiles/37-20161212040016656625/83ddeaa031bf68e602ce66af2d268317 (0.1ms)

编辑 2

当我binding.pry 进入_profile.html.erb 时,我得到以下信息:

[3] pry(#<#<Class:0x007f968480ec98>>)> current_user.roles.first
=> #<Role:0x007f969e4422a8 id: 1, name: "admin", resource_id: nil, resource_type: nil, created_at: Mon, 12 Sep 2016 00:38:47 UTC +00:00, updated_at: Mon, 12 Sep 2016 00:38:47 UTC +00:00>

我什至尝试了以下方法:

<% cache [current_user.roles.first.name, profile, @selected_profile, params[:rating]] do %>

当以非管理员用户身份登录时,它仍然给我与管理员用户相同的缓存结果。

编辑 3

这是调用集合的cache 块,该集合调用了_profile.html.erb

  <% cache @profiles do %>
    <div class="wrapper wrapper-content">
    <% @profiles.to_a.in_groups_of(3, false).each do |profiles| %>
        <div class="row">
            <%= render partial: "profile", collection: profiles %>
        </div>
    <% end %>
    </div>
  <% end %>

【问题讨论】:

  • 有没有可能嵌套在另一个缓存块中? current_user 在这个缓存块之前返回什么?
  • 我建议编写一个帮助规范或测试来检查缓存方法实际生成的内容。对我来说,出于某种原因,似乎有些东西正在通过一系列不同的配置文件强制递归。请注意不推荐您这样做的方式api.rubyonrails.org/classes/ActionView/Helpers/… 也许更简单的解决方案是重新考虑您想要的密钥
  • @EdmundLee 你是对的。它是嵌套的。我将父 cache block 添加为 Edit 3。刷新问题。
  • @marcamillion 你在 3 号还是 4 号轨道上?
  • @EdmundLee Rails 5.

标签: ruby-on-rails caching ruby-on-rails-5 russian-doll-caching


【解决方案1】:

您的父缓存阻止子缓存正常工作。您可以删除父缓存,也可以将其移至顶部,然后每个子缓存都可以分开

&lt;% cache @profiles do %&gt; 替换为:

<% cache [current_user.roles.first.try(:name), @profiles, @selected_profile, params[:rating]] do %>

然后是内部_profile.html.erb

<% cache [current_user.roles.first.try(:name), profile, @selected_profile, params[:rating]] do %>

【讨论】:

  • 所以这行得通,但我不确定它是否行得通,只是因为我删除了cache @profiles do。我最初确实尝试过,它确实有效。所以一旦我删除了最外层的缓存,这个问题就消失了。但我不想删除它。理想情况下,我希望能够从那里缓存它们。如何修复最外层的缓存以使其正常工作?
  • @marcamillion 您确定要为每个用户缓存相同的片段吗?好像是这样的逻辑
【解决方案2】:

根据 rails 的文档,您可以简单地将所有依赖项命名为缓存名称。参考ActionView::Helpers::CacheHelper#cache

由于您正在嵌套缓存(或称为Russian Doll Caching),因此您需要在最外层缓存块处命名嵌套缓存中的所有依赖项。像这样的:

<% cache [@profiles, current_user, current_user.roles] do <%>
  # ...
<% end %>

查看ActionView::Helpers::CacheHelper#fragment_name_with_digest 方法,它只是使用您传入的任何内容来构建缓存名称。因此,您只需要确保任何可能更改的内容都包含在任何受影响的缓存块中。

如果您使用的是 Rails 3

似乎并非如此,但请记住一些事情,请记住在缓存名称中添加一个版本,并在模板发生更改时更改版本。您将需要调整所有外部块的版本。或者选择使用 cache digest gem,它已经随 Rails 4 提供。

编辑

让我们在这里识别所有变量。您拥有呈现@profiles 集合的父视图。并且视图将根据当前用户是否是管理员而改变。不知道为什么params[:rating] 在这种情况下很重要。我也不确定@selected_profile 是干什么用的。但我认为它应该包括在内。

这就是我要做的。

# In User model, add a method to tell if it's an admin
# because "user.roles.first" seems fragile to me. what if the "roles" collection is sorted differently?
def admin?
  roles.where(name: 'admin').present?
end

# In the view
<% cache [@profiles, current_user, current_user.admin?, @selected_profile] do %>
  # ...

渲染集合时,实际上可以传入cached 选项。并且“如果您的集合缓存依赖于多个源(尽量避免这种情况以保持简单),您可以将所有这些依赖项命名为返回数组的块的一部分”,根据 herehere

<%= render partial: "profile", collection: profiles, cached: -> profile { [ profile, current_user, current_user.admin?, @selected_profile ] } %>

而且您不需要在部分缓存块中添加另一个缓存块。

【讨论】:

  • 我正在使用 Rails 5。不幸的是,仅将 current_user, current_user.roles 添加到外部缓存块似乎不起作用:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
相关资源
最近更新 更多