使用模板继承的俄罗斯娃娃缓存的问题

时间:2013-06-17 18:14:18

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

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

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

对于一个非常简单的示例,请考虑一个由两个控制器ThingOnes和ThingTwos组成的应用程序。此应用程序有一个布局(layouts/application.html.erb),只需使用:<%= render 'header' %>呈现头文件。

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

views/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调用退出缓存。它也比DRY更加WET(写一切两次),这是一个很大的关闭。

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

1 个答案:

答案 0 :(得分: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页面。