我确信已经提出过这个问题,但我找不到答案。
我有一个Project模型,它与我的客户端模型有belongs_to
的关系。客户端有一个名称,但项目不一定有客户端。
在我看来,我有这样的代码:
<%=h project.client && project.client.name %>
因为如果项目没有客户端,那么尝试访问project.client.name
会导致NoMethodError(nil
没有名为name
的方法。)
问题是,在视图中进行这种零检查是否可以接受,或者我是否应该寻找其他方法?
答案 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
中详细了解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
的几种情况。如果可能的话,我会尽量避免它们。如果你无法避免它们,我会将条件检查放在一个视图助手中,并为它添加一个辅助单元测试来验证(和记录)两个代码路径。