当我有一个可能存在或可能不存在的模型属性时,我需要在它之后链接一些方法,我添加present?
。例如:
Car.last.passengers.present? and
Car.last.passengers.each do { |passenger| puts passenger.name }
在这种情况下使用rescue
会更好吗?例如
Car.last.passengers.each { |passenger| puts passenger.name } rescue "No passengers in the car!"
修改
感谢所有回复。我应该问一个更一般的问题,“在一系列方法中间处理潜在nil
结果的最佳方法是什么?”。
为了清楚起见,让我举一些例子。如果我打电话:
Car.last.driver.pocket_contents
但Car
的最后一个实例没有driver
,我会在pocket_contents
上呼叫nil
。根据以下评论者之一,我应该使用try
,如果是这样,您能否告诉我在这种情况下如何简洁地使用它?
答案 0 :(得分:3)
绝对没有理由在这里使用rescue
。使用异常处理机制进行流量控制被广泛视为滥用异常,通常被视为不良做法。
还有可能没有理由使用x.present? && x.each
,因为(如果这是一个ActiveRecord关联)它将从不返回一个虚假的“不存在” “价值。它将始终返回一个类似于数组的对象,表示0个或更多项,您可以安全地调用each
。如果这不是ActiveRecord关联,则应更改代码以遵循此约定并返回空数组而不是nil
。
在一般情况下(假设ActiveSupport::CoreExtensions可用),您可以使用try
。假设passengers
是一种可能会返回nil
的方法,则您的.present?
检查应为try
次调用:
Car.last.passengers.try(:each) { ... }
这可以链接到artibtrary长度;这两者都是等价的:
a && a.b && a.b.c
a.try(:b).try(:c)
请注意,如果您的方法未返回nil
,而是返回"blank"值,则此方法无效。
如果try
不可用,那么您当前的解决方案是一种广泛使用的做法,除了您should be using &&
instead of and
- 这些不是Ruby中的等效运算符。
Car.last.passengers && Car.last.passengers.each { ... }
如果您想保存字符,可以使用||
代替&&
提供默认值,然后再采用您当前正在考虑的脏rescue
技巧:
(Car.last.passengers || []).each { ... }
如果是一个ActiveRecord关联,那么有几个惯用的Rails解决方案,其中最好的是移动你的“puts”(我假设实际上是渲染一系列HTML元素)成为自己的部分,称为_passenger.html.erb
。然后,您可以渲染整个集合:
= render Car.last.passengers
如果你想以不同的方式处理一个空集,你应该依赖于render
在呈现空集合时返回false
的行为:
= render Car.last.passengers || render 'no_cars'
这样,向用户显示“没有乘客”消息的标记存储在_no_cars.html.erb
部分中,并用一条线干净地呈现。
答案 1 :(得分:1)
您不希望挽救应发生的异常。如果预期行为属性可能不存在或对象可能为零,那么您可能希望使用try
或try!
方法。
如果你的对象不是nil,这将尝试调用方法/属性。 try
方法将悄悄地评估为nil,如果链上的某个地方无法完成。如果您尝试调用非零对象上不存在的方法,try!
方法将引发NoMethodError
。
答案 2 :(得分:0)
我无法告诉您问题中的代码在哪里,但我假设您正在尝试在视图中列出乘客姓名。如果您让乘客成为控制员的集合:
@passengers = @car.passengers.all
您的_passenger.html.erb部分内容可能为:
<%= passenger.name %>
如果集合为空,您可以在视图中渲染集合传递:
<%= render(@passengers) || "No passengers in the car!" %>
有关此内容的更多信息:http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials