Спасение Ruby и синтаксис лучших практик

У меня был код, похожий на этот:

foo = SomeActiveRecordModel.where(bar: 10).first.foo rescue ''

Как только я начал использовать Rubocop, он кричал на меня из-за синтаксиса восстановления. Итак, я подумал, что есть как минимум два других способа написать этот код:

foo = 
begin
  foo = SomeActiveRecordModel.where(bar: 10).first.foo
rescue NoMethodError
  ''
end

А также:

foo = SomeActiveRecordModel.where(bar: 10).first
foo.present? ? foo.foo : ''

Какой из этих способов будет предпочтительнее, или есть альтернативный способ, который предпочтительнее?


person CarlyL    schedule 21.12.2015    source источник
comment
Из любопытства, где вы это используете? Я вижу, что все три ответа вместе взятые являются выдающимися. Но если вы используете это в контроллере, возможно, было бы лучше переместить вызов метода where в scope или class method в SomeActiveRecordModel.   -  person vee    schedule 22.12.2015
comment
Это используется в методе класса. Он используется для захвата любых правил, существующих в базе данных, и применения этих правил к запросу sql.   -  person CarlyL    schedule 22.12.2015


Ответы (3)


Обычное эмпирическое правило состоит в том, что исключения должны быть зарезервированы для исключительных обстоятельств, которые вы не ожидаете в обычном потоке управления. Во-первых, они обычно медленнее, чем альтернативы.

Вот что я предпочитаю для вашего сценария:

foo = SomeActiveRecordModel.find_by_bar(10).try(:foo) || ''
person Mori    schedule 21.12.2015
comment
Или даже SomeActiveRecordModel.find_by(bar: 10).try(:foo) || '' или, возможно, SomeActiveRecordModel.find_by(bar: 10).try(:foo).to_s, поскольку foo предположительно является строкой. - person mu is too short; 22.12.2015
comment
Я видел подобный синтаксис раньше, но мне даже не пришло в голову попробовать. Спасибо за ваш ответ и время, которое вы тратите на его описание. - person CarlyL; 22.12.2015

Обработка исключений предназначена для обработки исключительных ситуаций. Понятно, что иногда записи может и не быть. Обработка этого с ловлей NoMethodError - абсолютно неправильный способ сделать это. Во-первых, он не только поймает «нет метода foo на nil: NilClass», но и все другие ошибки «нет метода», которые могут произойти (где-то опечатка и т. д.).

Таким образом, «запись не найдена», не являющаяся исключительной ситуацией, вы должны обрабатывать ее как таковую, с каким-то условным условием.

foo = SomeActiveRecordModel.where(bar: 10).first
return '' unless foo
foo.bar
person Sergio Tulentsev    schedule 21.12.2015
comment
Это имеет большой смысл. Спасибо, что нашли время, чтобы просветить меня по этому вопросу. - person CarlyL; 22.12.2015

Отныне ни один из этих способов не будет предпочтительным. Предпочтительным способом будет:

foo = SomeActiveRecordModel.where(bar: 10).first&.foo || ""
person sawa    schedule 21.12.2015
comment
Я чувствую, что этим новым оператором будут сильно злоупотреблять. :) - person Sergio Tulentsev; 22.12.2015
comment
Воу, воу, когда это случилось? И почему? - person zetetic; 22.12.2015
comment
@zetetic: ruby 2.3. Потому что причины. - person Sergio Tulentsev; 22.12.2015
comment
Это довольно изящно. Просто глядя на него, я ожидал, что он выдаст ошибку, если foo не существует, но я думаю, что это не так! Спасибо за ваш ответ/время! - person CarlyL; 22.12.2015