【问题标题】:Issues using Russian Doll Caching with Template Inheritance使用带有模板继承的俄罗斯娃娃缓存的问题
【发布时间】:2013-06-17 18:14:18
【问题描述】:

我一直在一个相当复杂的 Rails 应用程序的选定部分中相互独立地使用模板继承和俄罗斯娃娃缓存(使用 cache_digests gem),并取得了很大的成功。

我很难以理智的方式同时使用这两种技术,这让我怀疑我可能做错了什么......

举一个非常简单的例子,考虑一个由两个控制器组成的应用程序,ThingOnes 和 ThingTwos。这个应用程序有一个布局(layouts/application.html.erb),它简单地呈现一个头文件:<%= render 'header' %>

默认情况下,Rails 会在一堆位置中查找此部分,包括布局的视图目录 (views/application/_header.html.erb) 以及特定于当前控制器的任何位置 (如 views/thing_ones/_header.html.erbviews/thing_twos/_header.html.erb)。这意味着,出于缓存目的,我基本上有一个模板依赖列表(不包括引擎或其他任何东西),如下所示:

[
  "application/header",
  "thing_ones/header",
  "thing_twos/header"
]

现在,我们用缓存包装该渲染调用,如下所示:

<% cache 'header' do %>
  <%= render 'header' %>
<% end %>

不幸的是,运行 rake cache_digests:nested_dependencies TEMPLATE=layouts/application 会导致以下依赖项列表。

[
  "layouts/header"
]

它似乎根本不关心模板继承。修改未包含在列表中的文件具有修改未包含在列表中的文件的预期效果-缓存未正确过期并显示陈旧的标头。

这可以通过指定相关的模板路径来轻松解决,如下所示:

<% cache 'header' do %>
  <%# Template Dependency: application/header %>
  <%# Template Dependency: thing_ones/header %>
  <%# Template Dependency: thing_twos/header %>
  <%= render 'header' %>
<% end %>

这似乎确实是一个非常糟糕的解决方案,因为它不会很好地增长,并且需要大量琐碎的装饰来缓存调用以保留现有的模板继承行为。

同样,可以更明确地指定标头位置,如下所示:

<% cache 'header' do %>
  <%= render 'application/header' %>
<% end %>

这也无法保留现有的模板继承行为,使其不适合我们的需求。

最后一个选择是将cache 调用移动到标头部分本身。这不仅效率低下,因为它将render 调用排除在缓存之外。它也比 DRY 更 WET(将所有内容写两次),这是一个很大的障碍。

所以,要解决我的实际问题...我这样做是否正确?这似乎是一个相当大的缺点,会影响各种各样的实现,但我真的找不到很多与这个特定问题相关的讨论,所以我想知道其他人是否以一种更好的方式来做这件事。有没有更好的方法来做到这一点,或者至少为部分渲染自动指定整个模板依赖层次结构?

【问题讨论】:

  • 我开始怀疑人们只是没有在部署中保留这些缓存,或者其他什么......

标签: ruby-on-rails caching template-inheritance russian-doll-caching cache-digests


【解决方案1】:

这里的问题实际上是您最终建议自己的:您必须将cache 方法移动到渲染的模板中。

这可能看起来像更多代码,但这是缓存摘要正常工作所必需的。此外,如果您的部分(应用程序中的_header.html.erb,thing_ones 和 thing_twos)不同,那么缓存键也应该不同。这意味着你应该得到这样的结果:

# layouts/application.html.erb
<%= render 'header' %>

# application/_header.html.erb 
<% cache 'application_header' do %>
  ...
<% end %>

# thing_ones/_header.html.erb
<% cache 'thing_ones_header' do %>
  ...
<% end %>

# and thing_twos/_header.html.erb
<% cache 'thing_twos_header' do %>
  ...
<% end %>

如果没有不同的缓存键,这些缓存会相互覆盖,这意味着如果例如。 application/_header.html.erb 首先被缓存,然后将是呈现一个 ThingOnesThingTwos 页面的那个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-19
    • 1970-01-01
    • 2016-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多