Важно помнить, что в Ruby конечные !
или ?
разрешены для имен методов и становятся частью имени метода , а не модификатором. x
и x!
и x?
- это три совершенно разных метода.
В Ruby принято добавлять !
к методам, которые делают модификацию на месте , то естьони модифицируют объект фундаментальными способами. Примером этого является String#gsub
, который возвращает копию, и String#gsub!
, который изменяет строку на месте.
В Rails это было перенесено для обозначения этого, а также в ситуациях, когда метод вызовет исключение при ошибке вместо возврата nil
. Лучше всего это проиллюстрировать здесь:
Record.find_by(id: 10) # => Can return nil if not found
Record.find_by!(id: 10) # => Can raise ActiveRecord::RecordNotFound
Обратите внимание, что это не всегда так, поскольку такие методы, как find
, будут вызывать исключения даже без !
. Это чисто информационный компонент, встроенный в имя метода и не гарантирует, что он вызовет или не вызовет исключения.
Обновление :
Причина использования исключений заключается в том, чтосделать управление потоком легче. Если вы постоянно тестируете на nil
, вы в конечном итоге получаете очень параноидальный код, который выглядит следующим образом:
def update
if (user.save)
if (purchase.save)
if (email.sent?)
redirect_to(success_path)
else
render(template: 'invalid_email')
end
else
render(template: 'edit')
end
else
render(template: 'edit')
end
end
Другими словами, вам всегда нужно смотреть через плечо, чтобы убедиться, что ничего плохогоэто происходит. С исключениями это выглядит так:
def update
user.save!
purchase.save!
email.send!
redirect_to(success_path)
rescue ActiveRecord::RecordNotFound
render(template: 'edit')
rescue SomeMailer::EmailNotSent
render(template: 'invalid_email')
end
Там, где вы видите поток, гораздо проще понять. Он описывает «исключительные ситуации» как менее вероятные, чтобы они не загромождали основной код.