find () con zero quando non ci sono record


95

Nel mio attuale programma rails quando uso qualcosa di simile

 user = User.find(10)

Quando non ci sono utenti con ID = 10, avrò un'eccezione come:

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

Posso ottenere zero invece di sollevare eccezioni, quindi quando faccio qualcosa come:

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

Voglio solo ottenere zero quando non ci sono record e non voglio usare start / rescue

Grazie


Risposte:


170

Sì, basta fare:

Challenge.find_by_id(10)

Per i binari 4 e 5:

Challenge.find_by(id: 10)

11
dispari! Non avrei mai immaginato che .find_by_*sarebbe tornato zero e il .findnon sarebbe tornato .
ddavison

Questo è cambiato in rails 4, vedi questa risposta stackoverflow.com/a/26885027/1438478 per il nuovo modo di trovare un elemento in base a un attributo specifico.
Fralcon

Ho riscontrato uno strano problema con Rails 4.2 in cui quando si passa un hash come "x" Something.find_by(id: x)si crea un'istruzione SQL con tutte le coppie attributo / valore dell'hash come parte della clausola WHERE. A me sembra un bug di Rails.
Tilo

Rails (3, 4 o 5) genera find_by_...finder dinamici per ogni attributo incluso in un modello :id. Quindi, Challenge.find_by_id(10)dovrebbe funzionare indipendentemente dalla versione di Rails.
Arta

Come specificato da @MohamedIbrahim di seguito, puoi anche fare:Challenge.find(10) rescue nil
Hallgeir Wilhelmsen

31

In Rails 4, i finder dinamici, come quelli find_by_idusati nella risposta accettata, erano deprecati.

Andando avanti, dovresti usare la nuova sintassi:

Challenge.find_by id: 10

4
Nel caso qualcun altro sia confuso da questo come me: Challenge.find_by(id: 10)è l'altro modo di scrivere questo
Devin Howard

14

puoi farlo in modo un po 'hacker, usa semplicemente l'interfaccia di query di ActiveRecord.

questo restituirà zero, invece di sollevare un'eccezione

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

Un motivo per usarlo piuttosto che find_by_idè che è portabile da Rails 3 a 4. In rails 4, lo è find_by(:id => 10).
Gene

5

Perché non prendi semplicemente l'eccezione? Il tuo caso ha esattamente lo stesso aspetto delle eccezioni per:

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

Se vuoi recuperare dall'errore nel blocco di ripristino (ad esempio impostando un utente segnaposto (modello nullo)), puoi continuare con il tuo codice sotto questo blocco. Altrimenti potresti semplicemente mettere tutto il tuo codice per il "caso felice" nel blocco tra "inizio" e "salvataggio".


A proposito: non hai nemmeno bisogno del begin…endblocco, se hai già un blocco come un metodo controller. In tal caso l'unica linea extra di cui hai bisogno è la rescuelinea. Molto più elegante e più facile da gestire che controllare nilcon una ifdichiarazione.
morgler


4

Per coloro che lottano con mongoid , si scopre che sia finde find_bymetodi solleverà eccezioni - non importa la versione rotaie!

C'è un'opzione (vale a dire raise_not_found_error ) che può essere impostata su false, ma quando falsey fa il findmetodo non solleva neanche eccezioni.

Quindi la soluzione per gli utenti mongoidi è il codice disgustoso:

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

Cosa ne pensate della soluzione rescue nil di mohamed-ibrahim? Sembra più elegante di .where(email: params[:email]).firstme.
Wylliam Judd

1
Preferisco non usare quella rescuesintassi poiché può nascondere problemi come errori di battitura
Cristiano Mendonça

Ho finito per usare la soluzione di @ Morgler.
Wylliam Judd

2

semplice come:

user = User.find(10) rescue nil

1
Preferirei essere più specifico su quale errore dovrebbe essere salvato, ActiveRecord :: RecordNotFound in questo caso. Come sottolineato in questa risposta da @morgler
luizrogeriocn

2
Personalmente trovo che questa sia la risposta migliore. Sto già dicendo al mio codice cosa fare se l'utente non viene trovato inif user...else
Wylliam Judd

0

Puoi usare find_by con l'attributo richiesto (nel tuo caso l'id) questo restituirà nil invece di dare un errore se l'id dato non viene trovato.

user = Challenge.find_by_id(id_value)

oppure potresti usare il nuovo formato:

user = Challenge.find_by id: id_value

Puoi anche usare where ma devi sapere che where restituisce una relazione tra record attiva con zero o più record che devi usare prima per restituire un solo record o zero nel caso in cui vengano restituiti zero record.

user = Challenge.where(id: id_value).first
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.