是否有任何Rails函数来检查是否存在部分?


98

当我渲染不存在的部分时,出现异常。我想在渲染之前检查部分是否存在,如果不存在,我会渲染其他东西。我在.erb文件中执行了以下代码,但我认为应该有更好的方法:

    <% begin %>
      <%= render :partial => "#{dynamic_partial}" %>
    <% rescue ActionView::MissingTemplate %>
      Can't show this data!
    <% end %>

1
使用的答案rescue是有风险的。在使用它之前,我会先看看其他解决方案。
格兰特·哈钦斯

Answers:


98

当前,我在Rails 3 / 3.1项目中使用以下内容:

lookup_context.find_all('posts/_form').any?

与我见过的其他解决方案相比,优点在于,它可以在所有视图路径中查看,而不仅仅是您的rails根。这对我很重要,因为我有很多Rails引擎。

这也适用于Rails 4。


9
lookup_context.exists?('posts / find')对我不起作用。相反,在此示例中,我使用lookup_context.exists?(名称,前缀,部分)或lookup_content.exists?(“ find”,“ posts”,true)。
珍妮

2
这是当前(导轨> = 3.2)方法来检查模板(源apidock
maček

1
如果局部视图与当前视图模板位于同一文件夹中,则可以使用lookup_context.exists?("find", lookup_context.prefixes, true)。这样,您无需将视图目录硬编码到调用中。注意,这是局部的。对于非局部变量,省略最后一个arg(或使用false代替true)
Nathan Wallace

71

我也为此感到挣扎。这是我最终使用的方法:

<%= render :partial => "#{dynamic_partial}" rescue nil %>

基本上,如果部分不存在,则不执行任何操作。但是,如果缺少部分内容,是否要打印一些内容?

编辑1:哦,我听不懂理解力。您确实说过要渲染其他东西。在这种情况下,该怎么办?

<%= render :partial => "#{dynamic_partial}" rescue render :partial => 'partial_that_actually_exists' %>

要么

<%= render :partial => "#{dynamic_partial}" rescue "Can't show this data!" %>

编辑2:

替代方法:检查部分文件的存在:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>

6
我的问题是,我不希望使用异常做流量控制,这是一种反模式:stackoverflow.com/questions/1546514/...
丹尼尔Cukier

6
异常是一种流控制,用于处理超出程序正常操作范围的事情。如果动态部分应该存在,但出了点问题,但最终却不存在,那就是对例外的合理使用(当然,IMO-正确使用例外本身就是一场圣战)。我会说您的替代方法是检查文件系统中是否存在实际文件。我将用该代码更新答案。
杰夫

3
我喜欢这种解决方案,尽管如此,它可以吞噬部分中引发的任何异常。恕我直言,这使得查找错误更加困难。
马特

5
如果您有其他类型的异常,则rescue nil... rescue ...方法将其隐藏。这导致难以调试的错误。
nicholaides

8
我真的不喜欢这种解决方案。抢救很昂贵,并且File.exists存在?假设局部只能在一个位置。我相信@Rein使用lookup_context的解决方案是解决之道。
Bert Goethals '02

52

从内部来看,template_exists?可以,但是调用约定不适用于单个部分名称字符串,而是需要template_exists?(名称,前缀,部分)

要检查路径中的部分内容,请执行以下操作:app / views / posts / _form.html.slim

用:

lookup_context.template_exists?("form", "posts", true)

在Rails 3.0.10上,我发现如果我有一个备用扩展名,例如app / views / posts / _foo.txt.erb,则需要将其添加为以下参数:template_exists?((“ foo.txt”,“ posts” ,真实)
Gabe Martin-Dempesy 2011年

这在轨道弃用3.2
maček

在Rails 3.2.x中似乎没有委托它,但是,第二个参数是前缀数组。此外,它存在于当前控制器上。
布伦丹

2
您可以使用lookup_context.prefixes作为第二个参数:lookup_context.template_exists?(“ form”,lookup_context.prefixes,true)
lion.vollnhals 2014年

就从视图层访问此信息而言,这是更好的答案。
布伦登·缪尔

30

在Rails 3.2.13中,如果您在控制器中,则可以使用以下命令:

template_exists?("#{dynamic_partial}", _prefixes, true)

template_exists?委托给lookupcontext,你可以看到在AbstractController::ViewPaths

_prefixes 给出控制器继承链的上下文。

true 因为您正在寻找局部变量(如果需要常规模板,则可以忽略此参数)。

http://api.rubyonrails.org/classes/ActionView/LookupContext/ViewPaths.html#method-i-template_exists-3F


已投票。有关参数的最新信息和更好的解释。
jacobsimeon

4
从视图(如布局),此作品:lookup_context.template_exists?("navbar", controller._prefixes, :partial)。这可以告诉我当前呈现此布局的模板是否具有规定的“ navbar”部分,如果可以,可以进行渲染。我:partial只是为了明确表示布尔值是什么- :partial是真实的。谢谢你_prefixes,@ Flackou!
pdobb

如果要调用位于不同父目录中的部分,则替换_prefixesnil
2015年

8

我知道这个问题已经被回答,并且已有一百万年的历史了,但是这就是我最终为我解决这个问题的方式...

Rails 4.2

首先,我将其放在我的application_helper.rb中

  def render_if_exists(path_to_partial)
    render path_to_partial if lookup_context.find_all(path_to_partial,[],true).any?
  end

现在不用打电话

<%= render "#{dynamic_path}" if lookup_context.find_all("#{dynamic_path}",[],true).any? %>

我只是打电话 <%= render_if_exists "#{dynamic_path}" %>

希望能有所帮助。(尚未在rails3中尝试过)


1
如果您要提供备用广告,则此方法将无效。它也没有考虑局部变量。
phillyslick 2015年

这正是我想要的。很干净的答案。
2016年

1
@BenPolinsky我想您可以使用def render_if_exists(*args); render(*args) if ...
网站

6

我已经在很多场合成功使用了这种范例:

<%=
  begin
    render partial: "#{dynamic_partial}"
  rescue ActionView::MissingTemplate
    # handle the specific case of the partial being missing
  rescue
    # handle any other exception raised while rendering the partial
  end
%>

上面的代码的好处是我们可以处理以下两种特定情况:

  • 的确确实缺少了
  • 部分存在,但由于某种原因它引发了错误

如果仅使用代码<%= render :partial => "#{dynamic_partial}" rescue nil %>或某些派生代码,则部分代码可能存在,但会引发异常,该异常将被静默吃掉,并成为调试时的痛苦之源。


4

那你自己的帮手呢:

def render_if_exists(path, *args)
  render path, *args
rescue ActionView::MissingTemplate
  nil
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.