2015-11-16 5 views
0

Когда у меня есть атрибут модели, который может существовать или не существовать, и мне нужно связать некоторые методы после него, я добавляю present?. Например:Правильное использование `rescue` (или` try`)

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!" 

EDIT:

Спасибо за все ответы. Я должен был задать более общий вопрос: «Каков наилучший способ обработать потенциально nil результат в середине цепочки методов?».

Позвольте мне сделать мой пример более общим для ясности. Если я называю:

Car.last.driver.pocket_contents 

но последний экземпляр Car не имеет driver, я бы называть pocket_contents на nil. В соответствии с одним из комментаторов ниже, следует ли использовать try, и если да, не могли бы вы показать мне, как он будет использоваться лаконично в этом случае?

+1

обработка исключений является GE обычно для непредвиденных ошибок. Это нормальное состояние, или это действительно исключение? Если это нормально, вы хотите проверить «... пассажиры.представляете?» И отображать сообщение (если хотите) в зависимости от этого условия. Если вы пытаетесь сохранить код DRY, подумайте об использовании вспомогательного метода. – lurker

+6

Я бы сказал, что 'Car # passengers' должен возвращать пустой массив, когда в этом автомобиле нет пассажиров. Если это так, то вся проблема не существует. – spickermann

ответ

2

Там нет абсолютно никаких оснований для использования rescue здесь. Использование механизмов обработки исключений для управления потоком широко рассматривается как злоупотребление исключениями и обычно считается плохой практикой.

Там нет также вероятно никакой причины использовать x.present? && x.each, так как (если это объединение ActiveRecord) не будет никогда возвращают falsy «не-настоящее» значение. Он всегда будет возвращать массивный объект, представляющий 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 s) в свою собственную частицу, называемую _passenger.html.erb. Затем, вы можете сделать всю коллекцию:

= render Car.last.passengers 

Если вы хотите Отрисовку пустого множества по-разному, вы должны зависеть от поведения render «s возвращения false, когда пустая коллекция визуализируется:

= render Car.last.passengers || render 'no_cars' 

Таким образом, ваша разметка для отображения пользователю «Нет пассажиров» хранится в части _no_cars.html.erb и визуализируется чисто с помощью одной строки.

+0

Спасибо @meagar за очень тщательный ответ. Я считаю, что «попробовать» - это то, что я должен использовать, в соответствии с вашим ответом. Остальная часть вашего ответа была также очень полезной. Я не знал разницы между '&&' и 'and' –

1

Вы не хотите спасать исключение, которое должно произойти. Если ожидается, что атрибут не может существовать или объект может быть равен нулю, вы можете использовать методы try или try!.

Это попытается вызвать метод/атрибут, если ваш объект не равен нулю. Метод try будет спокойно оценивать нуль, если где-то вдоль цепочки он не может завершить. Метод try! поднимет NoMethodError, если вы попытаетесь вызвать метод, который не существует на объекте non nil.

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

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

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