find () z nil, gdy nie ma rekordów


96

W moim obecnym programie railsowym używam czegoś takiego jak

 user = User.find(10)

Gdy nie ma użytkownika o ID = 10, będę miał wyjątek taki jak:

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

Czy mogę uzyskać zero zamiast zgłaszać wyjątek, więc kiedy robię coś takiego:

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

Chcę tylko uzyskać zero, gdy nie ma rekordów i nie chcę używać rozpoczynania / ratowania

Dzięki


Odpowiedzi:


172

Tak, po prostu zrób:

Challenge.find_by_id(10)

Dla szyn 4 i 5:

Challenge.find_by(id: 10)

11
dziwny! Nigdy bym nie przypuszczał, .find_by_*że zwróci zero, a .findnie.
ddavison,

Zmieniło się to w listwach rails 4, zobacz tę odpowiedź stackoverflow.com/a/26885027/1438478, aby poznać nowy sposób znajdowania elementu według określonego atrybutu.
Fralcon

Znalazłem dziwny problem z Railsami 4.2, w którym po przekazaniu do niego skrótu jako „x” Something.find_by(id: x)utworzyłoby się instrukcję SQL ze wszystkimi parami atrybut / wartość hasha jako część klauzuli WHERE. Dla mnie wygląda na błąd w Railsach.
Tilo

Railsy (3, 4 lub 5) generują dynamiczne find_by_...wyszukiwarki dla każdego atrybutu, który zawiera model :id. Challenge.find_by_id(10)Powinien więc działać niezależnie od wersji Railsów.
Arta

Jak określono poniżej w @MohamedIbrahim, możesz również:Challenge.find(10) rescue nil
Hallgeir Wilhelmsen,

31

W Railsach 4, dynamiczne wyszukiwarki - takie jak find_by_idużyte w zaakceptowanej odpowiedzi - zostały wycofane.

Idąc dalej, powinieneś użyć nowej składni:

Challenge.find_by id: 10

4
Na wypadek, gdyby ktoś inny był zdezorientowany, tak jak ja: czy Challenge.find_by(id: 10)jest inny sposób pisania tego
Devin Howard

14

możesz to zrobić trochę hakersko, po prostu użyj interfejsu zapytań ActiveRecord.

zwróci to zero, zamiast zgłosić wyjątek

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

Powodem, dla którego należy tego używać, a nie find_by_iddlatego, że jest przenośny z Rails 3 do 4. W Rails 4 jest find_by(:id => 10).
Gene

5

Dlaczego po prostu nie złapiesz wyjątku? Twoja sprawa wygląda dokładnie tak, jak zostały stworzone wyjątki:

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

Jeśli chcesz naprawić błąd w bloku ratunkowym (np. Ustawiając użytkownika zastępczego (wzorzec null)), możesz kontynuować pracę z kodem poniżej tego bloku. W przeciwnym razie możesz po prostu umieścić cały kod „szczęśliwego przypadku” w bloku między „begin” i „rescue”.


Btw: nie potrzebujesz nawet begin…endbloku, jeśli masz już blok, taki jak metoda kontrolera. W takim przypadku jedyną dodatkową linią, której potrzebujesz, jest rescuelinia. O wiele bardziej eleganckie i łatwiejsze w obsłudze niż sprawdzanie za nilpomocą ifoświadczenia.
Morgler

4

Możesz tego spróbować Challenge.exists?(10)


7
będzie to dodatkowe żądanie sql
fl00r

Mimo to myślę, że lepiej jest szukać testów
SomeSchmo

używaj go, jeśli nie zależy Ci na zwracanej wartości, a jedynie na obecności rekordu w DB
Filip Bartuzi

4

Dla tych, którzy walczą z mangusty , okazuje się, że obie findi find_bymetody będą stanowić wyjątek - bez względu na wersję railsową !

Istnieje opcja (mianowicie raise_not_found_error ), która może być ustawiona na false, ale gdy falsey sprawia, że findmetoda również nie zgłasza wyjątku.

Tak więc rozwiązaniem dla użytkowników mongoidów jest obrzydliwy kod:

User.where(id: 'your_id').first # argghhh

Co myślisz o rozwiązaniu „Rescue Nil” autorstwa Mohameda-Ibrahima? Wydaje się bardziej eleganckie niż .where(email: params[:email]).firstdla mnie.
Wylliam Judd

1
Wolę nie używać tej rescueskładni, ponieważ może ona ukryć problemy, takie jak literówki
Cristiano Mendonça

Skończyło się na użyciu rozwiązania @ morgler.
Wylliam Judd

2

tak proste, jak:

user = User.find(10) rescue nil

1
Wolałbym bardziej precyzyjnie określić, jaki błąd ma zostać naprawiony, w tym przypadku ActiveRecord :: RecordNotFound. Jak wskazał na tę odpowiedź @morgler
luizrogeriocn

2
Osobiście uważam, że to najlepsza odpowiedź. Już mówię swojemu kodowi, co zrobić, jeśli użytkownika nie maif user...else
Wylliam Judd

0

Możesz użyć find_by z wymaganym atrybutem (w twoim przypadku id), to zwróci nil zamiast dawać błąd, jeśli podany id nie zostanie znaleziony.

user = Challenge.find_by_id(id_value)

lub możesz użyć nowego formatu:

user = Challenge.find_by id: id_value

Możesz również użyć gdzie, ale musisz wiedzieć, że jeśli zwracasz relację rekordu aktywnego z zerem lub większą liczbą rekordów, musisz najpierw użyć, aby zwrócić tylko jeden rekord lub zero w przypadku, gdy nie zwrócą żadnych rekordów.

user = Challenge.where(id: id_value).first
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.