web-dev-qa-db-fra.com

trouver vs find_by vs où

Je suis nouveau à Rails. Ce que je vois, c'est qu'il y a beaucoup de façons de trouver un disque:

  1. find_by_<columnname>(<columnvalue>)
  2. find(:first, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>).first

Et il semble que tous finissent par générer exactement le même code SQL. En outre, je pense que la même chose est vraie pour la recherche de plusieurs enregistrements:

  1. find_all_by_<columnname>(<columnvalue>)
  2. find(:all, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>)

Existe-t-il une règle empirique ou une recommandation sur laquelle utiliser?

115
Victor Ronin

Utilisez celui qui vous convient le mieux.

La méthode find est généralement utilisée pour récupérer une ligne par ID:

Model.find(1)

Il est à noter que find lève une exception si l'élément n'est pas trouvé par l'attribut que vous fournissez. Utilisez where (comme décrit ci-dessous, qui renverra un tableau vide si l'attribut n'est pas trouvé) pour éviter la génération d'une exception.

Les autres utilisations de find sont généralement remplacées par des choses comme celle-ci:

Model.all
Model.first

find_by est utilisé comme aide lorsque vous recherchez des informations dans une colonne et correspond aux conventions de dénomination. Par exemple, si vous avez une colonne nommée name dans votre base de données, vous utiliseriez la syntaxe suivante:

Model.find_by(name: "Bob")

.where est plus un piège qui vous permet d'utiliser une logique un peu plus complexe lorsque les helpers conventionnels ne le font pas, et renvoie un tableau d'éléments correspondant à vos conditions (ou un tableau vide sinon).

90
John

retourne ActiveRecord :: Relation

Examinons maintenant l'implémentation de find_by:

def find_by
  where(*args).take
end

Comme vous pouvez le voir, find_by est identique à mais il ne renvoie qu'un seul enregistrement. Cette méthode doit être utilisée pour obtenir 1 enregistrement et doit être utilisée pour obtenir tous les enregistrements avec certaines conditions.

120
Mike Andrianov

Il y a une différence entre find et find_by en ce que find renverra une erreur s'il n'est pas trouvé, alors que find_by renverra null.

Parfois, il est plus facile de lire si vous avez une méthode comme find_by email: "haha", par opposition à .where(email: some_params).first.

31
Kasumi

Model.find

1- Paramètre: ID de l'objet à trouver.

2- Si trouvé: Retourne l'objet (Un seul objet).

3- Si non trouvé: déclenche une exception ActiveRecord::RecordNotFound.

Model.find_by

1- Paramètre: clé/valeur

Exemple:

User.find_by name: 'John', email: '[email protected]'

2- Si trouvé: renvoie l'objet.

3- Si non trouvé: retourne nil.

Remarque: Si vous voulez que ce code soulève ActiveRecord::RecordNotFound, utilisez find_by!.

Model.where

1- Paramètre: identique à find_by

2- Si trouvé: Il retourne ActiveRecord::Relation contenant un ou plusieurs enregistrements correspondant aux paramètres.

3- Si non trouvé: Il retourne un ActiveRecord::Relation vide.

29
Hossam Khamis

Depuis Rails 4, vous pouvez faire:

User.find_by(name: 'Bob')

qui est l'équivalent find_by_name dans Rails 3.

Utilisez #where lorsque #find et #find_by ne suffisent pas.

17
Agis

La réponse acceptée couvre généralement tout, mais j'aimerais ajouter quelque chose, juste si vous prévoyez de travailler avec le modèle comme une mise à jour, et que vous récupérez un seul enregistrement (dont id vous ne le faites pas. savoir), alors find_by est la voie à suivre, car il récupère l’enregistrement et ne le met pas dans un tableau

irb(main):037:0> @kit = Kit.find_by(number: "3456")
  Kit Load (0.9ms)  SELECT "kits".* FROM "kits" WHERE "kits"."number" = 
 '3456' LIMIT 1
=> #<Kit id: 1, number: "3456", created_at: "2015-05-12 06:10:56",   
updated_at: "2015-05-12 06:10:56", job_id: nil>

irb(main):038:0> @kit.update(job_id: 2)
(0.2ms)  BEGIN Kit Exists (0.4ms)  SELECT 1 AS one FROM "kits" WHERE  
("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.5ms)   
UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE  "kits"."id" = 
1  [["job_id", 2], ["updated_at", Tue, 12 May 2015 07:16:58 UTC +00:00]] 
(0.6ms)  COMMIT => true

mais si vous utilisez where alors vous ne pouvez pas le mettre à jour directement

irb(main):039:0> @kit = Kit.where(number: "3456")
Kit Load (1.2ms)  SELECT "kits".* FROM "kits" WHERE "kits"."number" =  
'3456' => #<ActiveRecord::Relation [#<Kit id: 1, number: "3456", 
created_at: "2015-05-12 06:10:56", updated_at: "2015-05-12 07:16:58", 
job_id: 2>]>

irb(main):040:0> @kit.update(job_id: 3)
ArgumentError: wrong number of arguments (1 for 2)

dans un tel cas, vous devrez le spécifier comme ceci

irb(main):043:0> @kit[0].update(job_id: 3)
(0.2ms)  BEGIN Kit Exists (0.6ms)  SELECT 1 AS one FROM "kits" WHERE 
("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.6ms)   
UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE "kits"."id" = 1  
[["job_id", 3], ["updated_at", Tue, 12 May 2015 07:28:04 UTC +00:00]]
(0.5ms)  COMMIT => true
9
Leonard Kakande

Les deux # 2 de vos listes sont obsolètes. Vous pouvez toujours utiliser find(params[:id]) bien que.

Généralement, where() fonctionne dans la plupart des situations.

Voici un excellent post: http://m.onkey.org/active-record-query-interface

5
evanbikes

Outre la réponse acceptée, le suivi est également valide.

Model.find() peut accepter un tableau d'identifiants et renverra tous les enregistrements correspondants. Model.find_by_id(123) accepte également le tableau mais ne traitera que la première valeur d'identifiant présente dans le tableau

Model.find([1,2,3])
Model.find_by_id([1,2,3])
5
Saumya Mehta

Supposons que j'ai un utilisateur modèle

  1. User.find(id)

Retourne une ligne pointée par l'id. Donc supposons que si id = 1, alors il retournera la première ligne. Le type de retour sera objet utilisateur.

  1. User.find_by(email:"[email protected]")

Retourne la première ligne avec l'attribut ou l'e-mail correspondant dans ce cas. Le type de retour sera à nouveau l'objet User.

  1. User.where(project_id:1)

Renvoie tous les utilisateurs de la table users où les attributs correspondent. Ici, le type de retour sera l'objet ActiveRecord :: Relation contenant la liste des objets User.

2
Nikhil Mohadikar

Les réponses données jusqu'ici sont toutes correctes.

Cependant, une différence intéressante est que Model.find cherche par id; si trouvé, il retourne un objet Model (un seul enregistrement) mais jette un ActiveRecord::RecordNotFound sinon.

Model.find_by est très similaire à Model.find et vous permet de rechercher une colonne ou un groupe de colonnes dans votre base de données, mais renvoie nil si aucun enregistrement ne correspond à la recherche.

Model.where de son côté renvoie un objet Model::ActiveRecord_Relation qui ressemble à un tableau contenant tous les enregistrements qui correspondent à la recherche. Si aucun enregistrement n'a été trouvé, un objet Model::ActiveRecord_Relation vide est renvoyé.

J'espère que cela vous aidera à décider lequel utiliser à tout moment.

2
echelon