3

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

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

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

默认情况下,Rails 会在一堆位置中查找这个部分,包括布局的视图目录 ( views/application/_header.html.erb) 以及任何特定于当前控制器的位置 (likeviews/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(将所有内容写两次),这是一个很大的关闭。

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

4

1 回答 1

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页面的那个。

于 2013-06-20T08:11:55.853 回答