Je suis nouveau à Rails. Ce que je vois, c'est qu'il y a beaucoup de façons de trouver un disque:
find_by_<columnname>(<columnvalue>)
find(:first, :conditions => { <columnname> => <columnvalue> }
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:
find_all_by_<columnname>(<columnvalue>)
find(:all, :conditions => { <columnname> => <columnvalue> }
where(<columnname> => <columnvalue>)
Existe-t-il une règle empirique ou une recommandation sur laquelle utiliser?
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).
où 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 à où mais il ne renvoie qu'un seul enregistrement. Cette méthode doit être utilisée pour obtenir 1 enregistrement et où doit être utilisée pour obtenir tous les enregistrements avec certaines conditions.
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
.
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.
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.
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
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
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])
Supposons que j'ai un utilisateur modèle
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.
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.
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.
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.