在Rails视图中避免使用nil

时间:2010-08-21 12:34:31

标签: ruby-on-rails model-view-controller null

我确信已经提出过这个问题,但我找不到答案。

我有一个Project模型,它与我的客户端模型有belongs_to的关系。客户端有一个名称,但项目不一定有客户端。

在我看来,我有这样的代码:

<%=h project.client && project.client.name %>

因为如果项目没有客户端,那么尝试访问project.client.name会导致NoMethodError(nil没有名为name的方法。)

问题是,在视图中进行这种零检查是否可以接受,或者我是否应该寻找其他方法?

6 个答案:

答案 0 :(得分:10)

只需使用

project.client.try(:name)

答案 1 :(得分:3)

我认为它完全可以接受 - 这是视图逻辑,你或多或少根据是否有数据决定是否显示部分视图。

答案 2 :(得分:3)

我一直遇到这个问题,是的,这很烦人。即使假设永远不会是零,我继承的脏数据有时会触发它。

您的解决方案是处理它的一种方式。您还可以向名为Project的{​​{1}}添加一个方法,该方法显示客户端名称(如果存在),但是您将模型链接在一起的次数超出了一些人的推荐。

client_name

您也可以使用辅助方法来完成它,但最终可能会编写很多这样的方法。 :)

如下面的Skilldrick所述,这对添加默认字符串也很有用:

def client_name
  client && client.name
end

答案 3 :(得分:2)

您可以在delegate课程中使用Project,这样您就会尊重Law of demeter,表示您应该“只与您的直接朋友交谈”。

project.rb

class Project
  delegate :name, to: :client, prefix: true, allow_nil: true    
end

所以这样项目对象就会知道在哪里询问客户的名字:

#You can now call
project.client_name

Rails documentation.

中详细了解delegate

答案 4 :(得分:0)

我的hacky解决方案是产生一个块并拯救错误。许多人会说使用救援作为逻辑是非常糟糕的形式。只是不要使用这个你真正需要知道什么时候什么是零而不应该是。

在application_helper.rb中:

  def none_on_fail
      begin
          return yield
      rescue
          return "(none entered)"
      end
  end

然后在视图中:

<%= none_on_fail { project.client.name }  %>

然后可以将方法链接到所需的深度,并且可以在任何方法上使用它但是如果它们存在则它将掩盖模型/关系/方法的其他潜在问题。我会把它等同于用火焰喷射器取出碎片。如果使用不当,会产生非常有效的痛苦后果。

答案 5 :(得分:0)

我认为这些检查通常可以通过一些思考来消除。这样可以保持视图代码更清晰,更重要的是,将逻辑保留在视图层之外,这是最佳实践。一些模板引擎不允许视图中的任何逻辑。

至少有几种情况。假设您有一个取决于实例变量的show操作。我会说如果找不到记录,控制器不应该通过重定向或其他东西来渲染html。如果在视图中有一个数组的循环,请使用@array.each do |a| end,以便它不会评估数组是否为空。如果您确实希望视图中有应用程序默认值,请尝试从配置文件中加载它,例如@page_title || #{@APP_CONFIG['page_title']}(见Railscasts #85)。请记住,您可能希望稍后更改这些字符串,例如翻译UI。

这些是可以避免存在检查和使用try的几种情况。如果可能的话,我会尽量避免它们。如果你无法避免它们,我会将条件检查放在一个视图助手中,并为它添加一个辅助单元测试来验证(和记录)两个代码路径。