Quel est le moyen le plus efficace de vérifier si une base de données retournera un enregistrement avant de le traiter? Exemple: Truck.where("id = ?", id).select('truck_no').first.truck_no
Cela peut ou non renvoyer un camion si le camion existe. Quel est le moyen le plus efficace pour moi d’assurer que la page ne plantera pas lors du traitement de cette demande. Comment pourrais-je gérer cela à la fois dans la vue et dans le contrôleur si, disons, j'utilisais une boucle pour parcourir chaque camion et imprimer son numéro.
Si le document n'existe pas, j'aimerais pouvoir imprimer un message au lieu de dire qu'aucun document n'a été trouvé.
Si vous voulez vérifier l'existence d'un objet, pourquoi ne pas utiliser existe?
if Truck.exists?(10)
# your truck exists in the database
else
# the truck doesn't exist
end
Le exists?
La méthode présente l'avantage de ne pas sélectionner l'enregistrement dans la base de données (la signification est plus rapide que de sélectionner l'enregistrement). La requête ressemble à:
SELECT 1 FROM trucks where trucks.id = 10
Vous pouvez trouver plus d'exemples dans le documentation Rails pour #exists? .
Voici comment vous pouvez vérifier cela.
if Trucks.where(:id => current_truck.id).blank?
# no truck record for this id
else
# at least 1 record for this truck
end
où la méthode retourne un objet ActiveRecord :: Relation (agit comme un tableau contenant les résultats de où), il peut être vide mais jamais nul.
OP solution de cas d'utilisation réelle
La solution la plus simple consiste à combiner la vérification de votre base de données et la récupération des données dans une requête à une base de données au lieu d’avoir des appels de base de données distincts. Votre exemple de code est proche et traduit votre intention, mais sa syntaxe est légèrement différente.
Si vous faites simplement Truck.where("id = ?", id).select('truck_no').first.truck_no
et que cet enregistrement n'existe PAS, il générera une erreur nil
lorsque vous appelez truck_no
Car first
peut extraire un nil
record si aucun ne correspond à vos critères.
En effet, votre requête retournera un tableau d'objets correspondant à vos critères. Ensuite, vous effectuez un first
sur ce tableau qui (si aucun enregistrement correspondant n'est trouvé) est nil
.
Une solution assez propre:
# 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
Je recommande d'utiliser une syntaxe propre qui "se" commente afin que les autres sachent exactement ce que vous essayez de faire.
Si vous voulez vraiment faire un effort supplémentaire, vous pouvez ajouter une méthode à votre classe Truck
qui le fait pour vous et traduit votre intention:
# 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
Alors tu l'appellerais comme ceci:
if truck_number = Truck.truck_number_if_exists(id)
# do processing because record exists and you have the value
else
# no matching criteria
end
La méthode ActiveRecord.find_by
Récupérera le premier enregistrement correspondant à vos critères ou retournera nil
si aucun enregistrement n’est trouvé avec ce critère. Notez que l'ordre des méthodes find_by
Et where
est important; vous devez appeler le select
du modèle Truck
. En effet, lorsque vous appelez la méthode where
, vous retournez en fait un objet ActiveRelation
qui n’est pas ce que vous recherchez ici.
Voir API ActiveRecord pour la méthode 'find_by'
Des solutions générales utilisant 'existe?' méthode
Comme certains des autres contributeurs l'ont déjà mentionné, la méthode exists?
Est conçue spécifiquement pour vérifier l'existence de quelque chose. Il ne renvoie pas la valeur, mais confirme que la base de données a un enregistrement qui correspond à certains critères.
C'est utile si vous devez vérifier l'unicité ou l'exactitude de certaines données. La partie intéressante est qu’elle vous permet d’utiliser les critères ActiveRelation(Record?) where(...)
.
Par exemple, si vous avez un modèle User
avec un attribut email
et que vous devez vérifier si un courrier électronique existe déjà dans le dB:
User.exists?(email: "[email protected]")
L'avantage d'utiliser exists?
Est que l'exécution de la requête SQL est
SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
ce qui est plus efficace que de renvoyer des données.
Si vous avez besoin d'extraire conditionnellement des données de la base de données, ce n'est pas la méthode à utiliser. Cependant, cela fonctionne très bien pour une vérification simple et la syntaxe est très claire afin que les autres développeurs sachent exactement ce que vous faites. L'utilisation de la syntaxe appropriée est essentielle dans les projets avec plusieurs développeurs. Écrivez le code propre et laissez le code "commenter" lui-même.
Vous pouvez juste faire:
@truck_no = Truck.where("id = ?", id).pluck(:truck_no).first
Ceci retournera nil
si aucun enregistrement n'est trouvé, ou truck_no
de seulement le premier enregistrez autrement.
Ensuite, à votre avis, vous pouvez faire quelque chose comme:
<%= @truck_no || "There are no truck numbers" %>
Si vous voulez récupérer et afficher plusieurs résultats, alors dans votre contrôleur:
@truck_nos = Truck.where("id = ?", id).pluck(:truck_no)
et à votre avis:
<% truck_nos.each do |truck_no| %>
<%= truck_no %>
<% end %>
<%= "No truck numbers to iterate" if truck_nos.blank? %>
Si vous voulez juste vérifier si l’enregistrement existe ou non. Allez avec la réponse de @ cristian i.e.
Truck.exists?(truck_id) # returns true or false
Mais si les camions sortent, vous voulez accéder à ce camion, puis vous devrez le retrouver, ce qui entraînera deux interrogations dans la base de données. Si c'est le cas, allez avec
@trcuk = Truck.find_by(id: truck_id) #returns nil or truck
@truck.nil? #returns true if no truck is db
@truck.present? #returns true if no truck is db