2010-08-21 42 views
5

我确定已经有人问这个问题,但我找不到答案。避免在Rails视图中使用nil

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

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

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

,因为如果项目没有一个客户端,然后试图访问project.client.name导致NoMethodError(nil没有一个调用的方法name)。

问题是,在视图中是否可以接受这种类型的零检查,还是应该寻找其他方法?

回答

10

只需使用

project.client.try(:name) 
+0

我忘了那个...... :)但是,当你穿越5-6个模型时,它仍然会变得很沉重。 :( – DGM 2010-08-21 13:11:20

+3

http://en.wikipedia.org/wiki/Law_of_Demeter – Reactormonk 2010-08-21 14:00:05

+0

@Tass您对德米特法律是正确的,但我认为这不是正确的实施方式,请在下面看到我的帖子。 – dombesz 2014-01-08 17:06:56

3

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

3

我一直在遇到这种情况,而且这很烦人。即使应该从来没有零,我继承的脏数据有时会触发它。

您的解决方案是处理它的一种方法。您也可以在Project中添加一个名为client_name的方法,该方法会显示客户端名称(如果存在),但是您将模型链接在一起的次数超过某些人推荐的范围。

def client_name 
    client && client.name 
end 

你也可以做一个帮手的方法来做到这一点,但你最终可能会写很多。 :)

正如下面Skilldrick提到的,这也是有益的补充默认的字符串:

def client_name 
    client ? client.name : "no client" 
end 
+1

更多delegate这绝对是在某些情况下很有用(例如,如果你想要一个默认的名字,如“无客户端”)。 – Skilldrick 2010-08-21 16:50:27

+1

另一个不使用三元运算符的默认字符串实现:'client.name || “没有客户端” – Eric 2010-08-21 22:33:47

+0

当然,有人可能会争辩说,既然最初的问题是讨论有一个纯粹的mvc模型,那么通过在模型中放置一个默认的显示字符串,可能会将更多的视图逻辑注入到模型中,没有?这就是为什么我会按照提问者的方式做到这一点。但是,这都是风格,这也适用于:)。我只是不愿意假设我所做的每一个观点,我都想要相同的默认字符串,你知道吗? – jasonpgignac 2010-08-22 03:25:24

0

我哈克的解决办法是产生一个块,救出错误。许多人会说,使用救援作为逻辑是非常糟糕的形式。只是不要在实际需要知道何时不存在而不应该这样的情况下使用它。

在application_helper.rb:

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

然后在视图:

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

然后方法根据需要,它可以在任何方法来使用,但它会掩盖可以如深链如果模型/关系/方法存在其他潜在问题。我会将它等同于用火焰喷射器取出碎片。如果使用不当,会非常有效并带来痛苦的后果。

+1

非常Pythonic :) – Skilldrick 2010-08-21 19:45:29

0

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

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

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

2

您可以在您的Project课程中使用delegate,这样您就会尊重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.

相关问题