find () с nil, когда нет записей

96

В моей текущей программе rails, когда я использую что-то вроде

 user = User.find(10)

Когда нет пользователя с ID = 10, у меня будет исключение, например:

ActiveRecord::RecordNotFound: Couldn't find User with ID=10

Могу ли я получить nil вместо того, чтобы вызывать исключение, когда я делаю что-то вроде:

unless user = Challenge.find(10)
  puts "some error msg"         
end

Я просто хочу получить ноль, когда нет записей, и я не хочу использовать begin / rescue

Спасибо

Eqbal
источник

Ответы:

172

Да просто сделай:

Challenge.find_by_id(10)

Для Rails 4 и 5:

Challenge.find_by(id: 10)
апноэ
источник
11
странный! Я бы никогда не догадался, .find_by_*что возвращается nil, а the .findнет.
ddavison 07
Это изменилось в рельсах 4, см. Этот ответ stackoverflow.com/a/26885027/1438478, чтобы узнать о новом способе поиска элемента по определенному атрибуту.
Fralcon
Я обнаружил странную проблему с Rails 4.2, когда, когда вы передаете хэш как 'x', Something.find_by(id: x)он создает оператор SQL со всеми парами атрибут / значение хэша как часть предложения WHERE. Мне кажется, это ошибка Rails.
Тило
Rails (3, 4 или 5) генерирует динамические средства find_by_...поиска для каждого атрибута, который есть в модели :id. Итак, Challenge.find_by_id(10)должно работать независимо от версии Rails.
Arta
Как указано ниже @MohamedIbrahim, вы также можете:Challenge.find(10) rescue nil
Халльгейр Вильгельмсен,
31

В Rails 4 динамические средства поиска, такие как find_by_idиспользованные в принятом ответе, устарели.

В дальнейшем вам следует использовать новый синтаксис:

Challenge.find_by id: 10
Hattila91
источник
4
На случай, если кто-то еще смущен этим, как я: Challenge.find_by(id: 10)это другой способ написать это
Девин Ховард
14

вы можете сделать это немного хакерским, просто используйте интерфейс запросов ActiveRecord.

это вернет nil вместо исключения исключения

  User.where(:id => 10).first
шапочка
источник
Причина использовать это, а не find_by_idто, что он переносится с Rails 3 на 4. В rails 4 это find_by(:id => 10).
Джин
5

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

begin
  user = User.find(10)
rescue ActiveRecord::RecordNotFound
  puts "some error msg"
end

Если вы хотите исправить ошибку в блоке восстановления (например, установив пользователя-заполнителя (нулевой шаблон)), вы можете продолжить работу со своим кодом под этим блоком. В противном случае вы можете просто поместить весь свой код для «счастливого случая» в блок между «begin» и «rescue».

морглер
источник
Кстати: вам даже не нужен begin…endблок, если у вас уже есть такой блок, как метод контроллера. В этом случае единственная дополнительная линия, которая вам понадобится, - это rescueлиния. Гораздо элегантнее и проще в обращении, чем проверка nilс помощью ifоператора.
morgler 01
4

Вы можете попробовать это Challenge.exists?(10)

Tonymarschall
источник
7
это будет дополнительный запрос sql
fl00r 07
Тем не менее, я думаю, что это лучше для тестирования
SomeSchmo
используйте его, если вас не волнует возвращаемое значение, а только наличие записи в БД
Филип Бартузи
4

Для тех, кто борется с mongoid , оказывается, что оба метода findи вызовутfind_by исключение - независимо от вашей версии rails!

Существует опция (а именно, raise_not_found_error ), для которой может быть установлено значение false, но когда falsey делает findметод, также не вызывает исключение.

Таким образом, решение для пользователей монгоидов - это отвратительный код:

User.where(id: 'your_id').first # argghhh
Криштиану Мендонса
источник
Что вы думаете о спасительном решении Мохамеда-ибрахима? Кажется более элегантным, чем .where(email: params[:email]).firstмне.
Уиллиам Джадд
1
Я бы предпочел не использовать этот rescueсинтаксис, поскольку он может скрыть такие проблемы, как опечатки,
Криштиану Мендонса
Я закончил использовать решение @morgler.
Уиллиам Джадд
2

так же просто, как:

user = User.find(10) rescue nil
Мохамед-Ибрахим
источник
1
Я бы предпочел более конкретно указать, какая ошибка должна быть устранена, в данном случае ActiveRecord :: RecordNotFound. Как указано в этом ответе @morgler
luizrogeriocn
2
Я лично считаю, что это лучший ответ. Я уже говорю своему коду, что делать, если пользователь не найден вif user...else
Уиллиам Джадд
0

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

user = Challenge.find_by_id(id_value)

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

user = Challenge.find_by id: id_value

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

user = Challenge.where(id: id_value).first
Алануд Джаст
источник