2013-08-06 31 views
38

Qual è il metodo più efficace per verificare se un database restituirà un record prima di elaborarlo. Esempio: Truck.where("id = ?", id).select('truck_no').first.truck_noRails che verifica se esiste un record nel database

Questo può o non può restituire un camion se il carrello esiste. Qual è il modo più efficiente per assicurarmi che la pagina non si arresti in modo anomalo durante l'elaborazione di questa richiesta. Come gestirò questo sia nella vista che nel controller se diciamo che stavo usando un loop per passare attraverso ogni camion e stampare il suo numero.

Se il record non esiste, mi piacerebbe poter stampare un messaggio anziché dire che non è stato trovato alcun record.

+0

quale versione di rotaie stai? – Shaunak

+2

Dai un'occhiata a esiste?metodo http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F – cristian

risposta

82

Se si desidera verificare l'esistenza di un oggetto, perché non esiste l'uso?

if Truck.exists?(10) 
    # your truck exists in the database 
else 
    # the truck doesn't exists 
end 

Il metodo exists? ha il vantaggio che non è la selezione della record dal database (significato è più veloce di selezionare il record). La query si presenta come:

SELECT 1 FROM trucks where trucks.id = 10 

Potete trovare altri esempi in http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F

36

Ecco come è possibile controllare questo.

if Trucks.where(:id => current_truck.id).blank? 
    # no truck record for this id 
else 
    # at least 1 record for this truck 
end 

dove metodo restituisce un oggetto ActiveRecord :: Relation (agisce come un array che contiene i risultati della dove), può essere vuoto ma mai essere nullo.

+0

Ho sempre pensato che sarebbe tornato un nulla. Grazie per aver chiarito questo. – Bojan

+0

@ho appena fatto un downvoting. Si prega di aggiungere un commento, quindi aiuta a capire cosa c'è di sbagliato qui .. – Shaunak

+5

Usa 'esiste?' Insetad di 'vuoto?'. Questo eseguirà una query per verificare se l'oggetto esiste nel DB invece di recuperare l'intero oggetto. –

1

si può solo fare:

@truck_no = Truck.where("id = ?", id).pluck(:truck_no).first 

Ciò restituirà nil se non viene trovata alcuna traccia, o truck_no di solo il primo record di altrimenti.

Poi a suo avviso si può solo fare qualcosa di simile:

<%= @truck_no || "There are no truck numbers" %> 

Se si vuole recuperare e visualizzare più risultati, poi nel controller:

@truck_nos = Truck.where("id = ?", id).pluck(:truck_no) 

e nella vista:

<% truck_nos.each do |truck_no| %> 
    <%= truck_no %> 
<% end %> 

<%= "No truck numbers to iterate" if truck_nos.blank? %> 
+0

Grazie per il suggerimento. Non ho mai saputo del metodo Pluck. – Bojan

+0

Prego. 'pluck' selezionerà una singola colonna dal tuo tavolo. – Agis

8

OP uso reale soluzione caso

La soluzione più semplice è quella di combinare il vostro check-DB e il recupero dei dati in 1 Query DB invece di avere chiamate DB separate. Il tuo codice di esempio è vicino e trasmette il tuo intento, ma è un po 'fuori nella sintassi attuale.

Se fai semplice Truck.where("id = ?", id).select('truck_no').first.truck_no e questo record non esiste, sarà lanciare un errore nil quando si chiama truck_no perché first può recuperare un record nil se non si trovano i tuoi criteri.

Questo perché la query restituirà una matrice di oggetti che corrispondono ai criteri, quindi si esegue uno first su tale array che (se non vengono trovati record corrispondenti) è nil.

Una soluzione abbastanza pulito:

# Note: using Rails 4/Ruby 2 syntax 
first_truck = Truck.select(:truck_no).find_by(id) # => <Truck id: nil, truck_no: "123"> OR nil if no record matches criteria 

if first_truck 
    truck_number = first_truck.truck_no 
    # do some processing... 
else 
    # record does not exist with that criteria 
end 

mi consiglia di utilizzare la sintassi pulita che "commenti" se stessa in modo che gli altri sanno esattamente quello che stai cercando di fare.

Se davvero si vuole andare il miglio supplementare, si potrebbe aggiungere un metodo alla classe Truck che fa questo per voi e trasmette il vostro intento:

# truck.rb model 
class Truck < ActiveRecord::Base 
    def self.truck_number_if_exists(record_id) 
    record = Truck.select(:truck_no).find_by(record_id) 
    if record 
     record.truck_no 
    else 
     nil # explicit nil so other developers know exactly what's going on 
    end 
    end 
end 

allora si sarebbe chiamarla in questo modo:

if truck_number = Truck.truck_number_if_exists(id) 
    # do processing because record exists and you have the value 
else 
    # no matching criteria 
end 

Il metodo ActiveRecord.find_by recupera il primo record che corrisponde ai criteri o restituisce nil se non viene trovato alcun record con tali criteri. Si noti che l'ordine dei metodi find_by e where è importante; devi chiamare lo select sul modello Truck. Questo perché quando chiami il metodo where stai effettivamente restituendo un oggetto ActiveRelation che non è quello che stai cercando qui.

See ActiveRecord API for 'find_by' method

soluzioni generali usando 'esiste?' metodo

Come alcuni degli altri contributori hanno già menzionato, il metodo exists? è stato progettato specificamente per verificare l'esistenza di qualcosa. Non restituisce il valore, solo conferma che il DB ha un record che corrisponde ad alcuni criteri.

È utile se è necessario verificare l'univocità o la precisione di alcuni dati. La parte interessante è che ti consente di utilizzare i criteri ActiveRelation(Record?) where(...).

Per esempio, se si dispone di un modello di User con un attributo email ed è necessario verificare se una e-mail esiste già nella dB:

User.exists?(email: "[email protected]")

Il vantaggio di utilizzare exists? è che la query SQL corsa è

SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1

che è più efficiente di dati effettivamente ritorno.

Se è necessario recuperare in modo condizionale i dati dal DB, questo non è il metodo da utilizzare. Tuttavia, funziona alla grande per un semplice controllo e la sintassi è molto chiara, così altri sviluppatori sanno esattamente cosa stai facendo. L'uso della sintassi appropriata è fondamentale nei progetti con più sviluppatori. Scrivi un codice pulito e lascia che il codice "commenta" stesso.

+2

questa è una guida molto utile, grazie –

+0

In ruby ​​qualsiasi funzione che restituisce true o false quale è 'truck_number_if_exists (id) 'nel tuo caso, dovrebbe avere un punto interrogativo alla fine – ImranNaqvi

+0

@ImranNaqvi: hai ragione che la convenzione in Ruby sta per aggiungere '?' Ai metodi booleani; tuttavia, in questo caso, 'truck_number_if_exist (id)' non è un metodo booleano; restituisce un valore se ne esiste uno altrimenti restituisce zero. Poiché non è un metodo booleano, non dovrebbe usare un '?' Alla fine. –

Problemi correlati