Rails 2: Model.find(1) дает ошибку ActiveRecord, когда id 1 не существует

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

Ответ 1

Это ожидаемое поведение. Я думаю, что Дэвид объясняет это самым лучшим, поэтому вот цитата из Ruby, S., Thomas, D. and Hansson, DH, 2009. Agile Web Development с Rails, Третье издание третьего издания., Прагматическая книжная полка (стр .330).

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

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

Ответ 2

Если вы действительно не хотите исключение, вы можете использовать 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?.

EDIT: Обратите внимание, что, как прокомментировал @Miguelgraz, в Rails 4 вы должны сказать User.find_by(id: params[:id]). Такая же функциональность, но теперь для реализации не потребуется method_missing.

Ответ 3

бросание исключения - ожидаемое поведение.

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

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

begin
  @model = Model.find(id_provided)
rescue ActiveRecord::RecordNotFound => e
  @model = nil
end

Ответ 4

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

Например,

Model.find_by_category!(a_category_value)

выкинет RecordNotFound, если совпадение не найдено.

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

Ответ 5

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

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

Ответ 6

Метод Rails 4

if user = User.find_by(id: params[:id]) 
  #do something with user
else
  #throw error or redirect
  raise ActiveRecord::RecordNotFound
end

Ответ 7

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

Model.find_by_id(id_value)

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

Model.where(id: id_value).first

Ответ 8

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

user = User.find(10) rescue nil