find () з нулем, коли немає записів


95

У моїй поточній програмі rails, коли я використовую щось на зразок

 user = User.find(10)

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

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

Чи можу я отримати нуль замість того, щоб викликати виняток, тому, коли я роблю щось на зразок:

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

Я просто хочу отримати нуль, коли немає записів, і я не хочу використовувати початок / порятунок

Дякую


Відповіді:


170

Так, просто зробіть:

Challenge.find_by_id(10)

Для рейок 4 і 5:

Challenge.find_by(id: 10)

11
дивно! Я ніколи не здогадався .find_by_*б, що поверне нуль, а .findні.
ddavison

Це змінилося у напрямках 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.
Арта

Як зазначено нижче @MohamedIbrahim, ви також можете зробити:Challenge.find(10) rescue nil
Hallgeir Wilhelmsen

31

У Rails 4 динамічні шукачі - такі, find_by_idякі були використані у прийнятій відповіді - застаріли.

Рухаючись вперед, слід використовувати новий синтаксис:

Challenge.find_by id: 10

4
На випадок, якщо когось ще це збентежить, як мене: Challenge.find_by(id: 10)чи це інший спосіб написати це
Девін Говард

14

ви можете зробити це трохи хакерсько, просто скористайтеся інтерфейсом запитів ActiveRecord.

це поверне нуль, замість того, щоб викликати виняток

  User.where(:id => 10).first

Причиною використання цього, а не того find_by_id, що він портативний з Rails 3 до 4. У Rails 4, це find_by(:id => 10).
Gene

5

Чому б вам просто не вловити виняток? Ваша справа виглядає точно так, для чого були зроблені винятки:

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

Якщо ви хочете відновити помилку в блоці порятунку (наприклад, встановивши користувача-заповнювач (нульовий шаблон)), ви можете продовжити свій код нижче цього блоку. В іншому випадку ви можете просто помістити весь свій код для "щасливого випадку" в блок між "почати" та "врятувати".


До речі: вам навіть не потрібен begin…endблок, якщо у вас вже є такий блок, як метод контролера. У цьому випадку вам потрібна лише додаткова rescueлінія. Набагато елегантніше та простіше в обробці, ніж перевіряти nilнаявність ifзаяви.
morgler

4

Ви можете спробувати це Challenge.exists?(10)


7
це буде додатковий запит на sql
fl00r

Незважаючи на це, я думаю, що це краще шукати для тестування
SomeSchmo

використовуйте його, якщо вам байдуже повернене значення, а лише наявність запису в БД
Філіп Бартузі

4

Для тих, хто бореться з монгоїдом , виявляється, що обидва способи findі find_byметоди викликають виняток - незалежно від вашої версії рейок!

Існує опція (а саме 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
Wylliam Judd

0

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

user = Challenge.find_by_id(id_value)

або ви можете використовувати новий формат:

user = Challenge.find_by id: id_value

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

user = Challenge.where(id: id_value).first
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.