正确使用`rescue`(或`try`)

时间:2015-11-16 16:07:35

标签: ruby-on-rails ruby

当我有一个可能存在或可能不存在的模型属性时,我需要在它之后链接一些方法,我添加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,如果是这样,您能否告诉我在这种情况下如何简洁地使用它?

3 个答案:

答案 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)

您不希望挽救应发生的异常。如果预期行为属性可能不存在或对象可能为零,那么您可能希望使用trytry!方法。

如果你的对象不是nil,这将尝试调用方法/属性。 try方法将悄悄地评估为nil,如果链上的某个地方无法完成。如果您尝试调用非零对象上不存在的方法,try!方法将引发NoMethodError

http://apidock.com/rails/v4.2.1/Object/try%21

http://apidock.com/rails/Object/try

答案 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