Rails: проверить, не существует ли ID в контроллере?

Можно ли сделать следующее:

if @user = User.friendly.find(params[:id])
    // logic here
else
    // do something if user doesn't exist
end

По какой-то причине это вызывает следующую ошибку:

ActiveRecord::RecordNotFound


person Hopstream    schedule 29.12.2013    source источник
comment
Можете ли вы показать еще немного кода? Код модели для пользователя? Фактический вывод веб-сервера, когда вы делаете этот запрос?   -  person Beartech    schedule 29.12.2013
comment
Это ожидаемо - stackoverflow.com/a/9709849/2864740   -  person user2864740    schedule 29.12.2013


Ответы (2)


Это ожидаемо.

[] RecordNotFound [исключение возникает, если] ни одна запись не ответила на метод find. Либо строка с данным идентификатором не существует, либо строка не соответствует дополнительным ограничениям. Некоторые вызовы поиска [например, методы find_by*] не вызывают это исключение, чтобы сигнализировать о том, что ничего не найдено.

Используйте find_by_id (или find_by), который вернет nil, если элемент не найден:

friendly.find_by_id params[:id]
friendly.find_by id: params[:id]

См. также: Rails находит получение ActiveRecord::RecordNotFound

person user2864740    schedule 29.12.2013

Как было предложено в Rails находит получение ActiveRecord::RecordNotFound, я бы использовал begin/end, потому что .find должен вызвать исключение:

begin
  @user = User.friendly.find(params[:id])
  # rest of code...
rescue ActiveRecord::RecordNotFound => e
  # other code; @user will automatically be nil since unassigned
end

Но на самом деле это вопрос личных предпочтений.

person weltschmerz    schedule 29.12.2013
comment
Что быстрее? find или find_by_id? - person Hopstream; 29.12.2013
comment
Скорость @Hopstream такая же. Нет никакой внутренней причины выбирать один из них в зависимости от производительности - просто ваши предпочтения и то, как вы хотите структурировать код :) - person user2864740; 29.12.2013
comment
@Hopstream Технически find быстрее. Я сделал тест производительности на обоих 10 раз. find заняло в среднем 0,001148 секунды, find_by_id заняло в среднем 0,001741 секунды. - person weltschmerz; 29.12.2013
comment
@Charles При использовании begin/rescue в контроллере должен ли шаблон вызываться после спасения? - person Hopstream; 29.12.2013
comment
Оператор begin/end не влияет на отрисовку представления. Если при спасении вы не хотите отображать представление, просто return false внутри блока восстановления, чтобы остановить метод контроллера, или, более элегантно, redirect_to some_path and return false - person weltschmerz; 29.12.2013