Rails 2: Model.find (1) выдает ошибку ActiveRecord, когда id 1 не существует - PullRequest
30 голосов
/ 11 февраля 2011

Я использую Rails 2.3.5, и в этом случае, если я даю Model.find(1) и если 1 отсутствует в базе данных, он возвращает ошибку ActiveRecord. Должен ли он просто возвращать nil, как в случае Model.find_by_column('..')?

Ответы [ 8 ]

57 голосов
/ 11 февраля 2011

Это ожидаемое поведение. Я думаю, что Дэвид сам объясняет это лучше всего, поэтому вот цитата из Руби С., Томаса Д. и Ханссона, Д.Х., 2009 г. Agile Web Development с Rails , третье Выпуск третье издание., Прагматическая книжная полка (с.330).

Когда вы используете видоискатель, управляемый первичные ключи, вы ищете конкретная запись. Вы ожидаете, что это существовать. Вызов Person.find (5) основываясь на наших знаниях людей Таблица. Мы хотим строку с идентификатором 5. Если этот вызов неудачен - если запись с идентификатором 5 была уничтожены - мы в исключительном ситуация. Это требует повышения исключения, поэтому рейлс поднимает Запись не найдена.

С другой стороны, искатели, которые используют критерии для поиска ищем матч. Так, Person.find (: во-первых, : condition => "name =’ Dave ’") эквивалент рассказывать базу данных (как черный ящик) «Дайте мне первого человека строка, которая имеет имя Дейв ". Это демонстрирует отчетливо разные подход к поиску; мы не уверены, что получим результат заранее. Вполне возможно, набор результатов может быть пустым. Таким образом, возвращая ноль в случай искателей, которые ищут одна строка и пустой массив для поиска этот поиск для многих строк является естественный, неисключительный ответ.

24 голосов
/ 10 марта 2011

Если вы действительно не хотите исключения, вы можете использовать find_by_id:

# @user = User.find(params[:id])    # original code
@user = User.find_by_id(params[:id])
if @user
    # found!
else
    # not found
end

Это должно быть быстрее, чем отдельный exists? чек.

РЕДАКТИРОВАТЬ: Примечаниечто, как прокомментировал @Miguelgraz, в Rails 4 вы должны вместо этого сказать User.find_by(id: params[:id]).Та же функциональность, но теперь для реализации не потребуется method_missing.

5 голосов
/ 11 февраля 2011

исключение является ожидаемым поведением.

на самом деле в нормальном ходе событий, если вы оставите исключение необработанным, ваш сервер rails вернет правильную ошибку 404 страница не найдена.

если вы хотите, чтобы он вернул ноль, вы можете поймать его самостоятельно:

begin
  @model = Model.find(id_provided)
rescue ActiveRecord::RecordNotFound => e
  @model = nil
end
2 голосов
/ 30 апреля 2013

Если вы хотите, чтобы исключение было добавлено в ароматы find_by_attributes методов поиска, вы можете использовать взрыв! версия метода.

Например,

Model.find_by_category!(a_category_value)

сгенерирует RecordNotFound, если совпадений не найдено.

Я обнаружил, что это СУХОЙ в сценариях, таких как контроллеры RESTful, где у меня есть общий обработчик ошибок для исключения, и я хочу, чтобы мои действия вели себя согласованно, когда ресурс, соответствующий заданным параметрам, не найден.

1 голос
/ 02 декабря 2014

Метод Rails 4

if user = User.find_by(id: params[:id]) 
  #do something with user
else
  #throw error or redirect
  raise ActiveRecord::RecordNotFound
end
0 голосов
/ 19 декабря 2016

Вы можете просто использовать:

user = User.find(10) rescue nil
0 голосов
/ 04 октября 2016

Вы можете использовать find_by с обязательным атрибутом (в вашем случае идентификатором), это вернет nil вместо сообщения об ошибке, если данный идентификатор не найден.

Model.find_by_id(id_value)

Вы также можете использовать , где , но вы должны знать, что для возврата отношения активной записи с нулевым или большим количеством записей вам нужно сначала использовать, чтобы вернуть только одну запись или ноль в случае возврата нулевых записей.

Model.where(id: id_value).first
0 голосов
/ 11 февраля 2011

Вы можете проверить, существует ли запись перед ее извлечением.

@model = Model.find(id) if Model.exists?(id)
...