find vs find_by vs where


127

Ich bin neu in Schienen. Was ich sehe, dass es viele Möglichkeiten gibt, eine Aufzeichnung zu finden:

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

Und es sieht so aus, als würden alle genau das gleiche SQL generieren. Ich glaube auch, dass das Gleiche für das Auffinden mehrerer Datensätze gilt:

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

Gibt es eine Faustregel oder eine Empfehlung für die Verwendung?

Antworten:


103

Verwenden Sie das, was Ihrer Meinung nach Ihren Anforderungen am besten entspricht.

Die findMethode wird normalerweise verwendet, um eine Zeile anhand der ID abzurufen:

Model.find(1)

Es ist erwähnenswert, dass findeine Ausnahme ausgelöst wird, wenn der Artikel nicht von dem von Ihnen angegebenen Attribut gefunden wird. Verwenden Sie where(wie unten beschrieben, um ein leeres Array zurückzugeben, wenn das Attribut nicht gefunden wird), um zu vermeiden, dass eine Ausnahme ausgelöst wird.

Andere Verwendungen von findwerden normalerweise durch folgende Dinge ersetzt:

Model.all
Model.first

find_bywird als Hilfsmittel verwendet, wenn Sie nach Informationen in einer Spalte suchen, und wird solchen mit Namenskonventionen zugeordnet. Wenn Sie beispielsweise eine Spalte namein Ihrer Datenbank haben, verwenden Sie die folgende Syntax:

Model.find_by(name: "Bob")

.where Dies ist eher ein Haken, mit dem Sie eine etwas komplexere Logik verwenden können, wenn die herkömmlichen Helfer dies nicht tun, und es wird ein Array von Elementen zurückgegeben, die Ihren Bedingungen entsprechen (oder ein leeres Array ansonsten).


62
find_byist nicht veraltet, aber die Syntax ändert sich ein wenig. Von find_by_name("Bob")bis find_by(:name, "Bob").
Brian Morearty

61
@ BrianMorearty Ich glaube, Sie meintenfind_by(name: "Bob")
MCB

1
@BrianMorearty Ich konnte keine Beweise dafür finden, dass ich veraltet bin. Hast find_by_...du eine Quelle? Es scheint find_byund find_by_...werden beide noch in Rails 4 unterstützt.
Dennis

4
@ Tennis, Sie haben Recht, dass es nicht veraltet ist, und das habe ich gesagt. Aber ich hätte klarer sein können, als ich sagte "aber die Syntax ändert sich ein bisschen." Was ich meinte war, "aber eine neue Syntax ist jetzt auch verfügbar." Siehe die Korrektur von MCB für die neue Syntax.
Brian Morearty

3
Dies ist, was in der Rails 4.0-Version "Alle dynamischen Methoden außer find_by _... und find_by _...! Veraltet sind" erwähnt wird. Weitere Details zu edgeguides.rubyonrails.org/…
Mukesh Singh Rathaur

131

Dabei wird ActiveRecord :: Relation zurückgegeben

Schauen Sie sich nun die Implementierung von find_by an:

def find_by
  where(*args).take
end

Wie Sie sehen können, ist find_by dasselbe wie where , gibt jedoch nur einen Datensatz zurück. Diese Methode sollte verwendet werden, um 1 Datensatz abzurufen, und wo sollte verwendet werden, um alle Datensätze unter bestimmten Bedingungen abzurufen.


1
find_by gibt ein Objekt zurück, wobei where eine Sammlung zurückgibt.
Kick Buttowski

Wenn Abfragewert außerhalb des Bereichs, find_bywird Rettung ::RangeErrorvon where(*args) und Rückkehr gleich Null.
Fangxing

34

Model.find

1- Parameter: ID des zu suchenden Objekts.

2- Wenn gefunden: Gibt das Objekt zurück (nur ein Objekt).

3- Wenn nicht gefunden: Löst eine ActiveRecord::RecordNotFoundAusnahme aus.

Model.find_by

1- Parameter: Schlüssel / Wert

Beispiel:

User.find_by name: 'John', email: 'john@doe.com'

2- Wenn gefunden: Gibt das Objekt zurück.

3- Wenn nicht gefunden: kehrt zurück nil.

Hinweis: Wenn Sie möchten, dass dieActiveRecord::RecordNotFoundVerwendungerhöhtwirdfind_by!

Model.where

1- Parameter: wie find_by

2- Wenn gefunden: Es wird ActiveRecord::Relationein oder mehrere Datensätze zurückgegeben, die den Parametern entsprechen.

3- Wenn nicht gefunden: Es wird ein Leerzeichen zurückgegeben ActiveRecord::Relation.


31

Es gibt einen Unterschied zwischen findund find_bydarin, dass findein Fehler zurückgegeben wird, wenn er nicht gefunden wird, während find_bynull zurückgegeben wird.

Manchmal ist es einfacher zu lesen, wenn Sie eine Methode wie find_by email: "haha"im Gegensatz zu haben .where(email: some_params).first.


17

Seit Rails 4 können Sie:

User.find_by(name: 'Bob')

Das ist das Äquivalent find_by_namein Rails 3.

Verwenden Sie, #wherewenn #findund #find_bynicht genug sind.


2
Agis, ich stimme Ihnen zu, aber ich habe über das Internet gesucht, warum wir verwenden sollten find_byund nicht find_by_<column_name>. Ich brauche es, um jemandem zu antworten.
KULKING

Agis, haben Sie Quellen, um Ihre Behauptung zu untermauern, dass wir sie nicht mehr find_by_namein Rails 4 verwenden sollten? Soweit ich weiß, ist es nicht veraltet .
Dennis

Gibt es eine einfache Möglichkeit, dies zu tun, aber sagen Sie, dass der Name einen Platzhalter enthält, also so etwas wiefind_by(name: "Rob*")
Batman

1
@ Tennis Es ist möglich, beide zu verwenden, sie sind gültig. Ich bevorzuge die neue Syntax, da die API meiner Meinung nach intuitiver ist. So würde ich es selbst gestalten :)
Agis

8

Die akzeptierte Antwort deckt im Allgemeinen alles ab, aber ich möchte etwas hinzufügen, nur für den Fall, dass Sie planen, mit dem Modell auf eine Art und Weise wie das Aktualisieren zu arbeiten, und Sie einen einzelnen Datensatz abrufen (dessen id Sie nicht wissen), dann find_byist der richtige Weg, weil es den Datensatz abruft und ihn nicht in ein Array legt

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

aber wenn du verwendest where , können Sie es nicht direkt aktualisieren

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)

In einem solchen Fall müssten Sie es so angeben

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

genau das, wonach ich gesucht habe
Paul Brunache

2
@kit = Kit.where (Nummer: "3456"). first - Damit können Sie es direkt aktualisieren und es ist sicherer, da es die Verwerfung überlebt hat
Paul Brunache

6

Neben der akzeptierten Antwort gilt auch Folgendes

Model.find()kann ein Array von IDs akzeptieren und gibt alle übereinstimmenden Datensätze zurück. Model.find_by_id(123)Akzeptieren Sie auch das Array, verarbeiten Sie jedoch nur den ersten im Array vorhandenen ID-Wert

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


3

Die bisher gegebenen Antworten sind alle in Ordnung.

Ein interessanter Unterschied besteht jedoch darin, dass Model.findnach ID gesucht wird. Wenn es gefunden wird, gibt es ein ModelObjekt zurück (nur einen einzelnen Datensatz), löst aber ein ActiveRecord::RecordNotFoundanderes aus.

Model.find_byist sehr ähnlich zu Model.findund lässt Sie jede Spalte oder Gruppe von Spalten in Ihrer Datenbank durchsuchen, gibt jedoch zurück, nilwenn kein Datensatz mit der Suche übereinstimmt.

Model.whereAuf der anderen Seite wird ein Model::ActiveRecord_RelationObjekt zurückgegeben, das genau wie ein Array ist, das alle Datensätze enthält, die mit der Suche übereinstimmen . Wenn kein Datensatz gefunden wurde, wird ein leeres Model::ActiveRecord_RelationObjekt zurückgegeben.

Ich hoffe, diese helfen Ihnen bei der Entscheidung, welche Sie zu irgendeinem Zeitpunkt verwenden möchten.


3

Angenommen, ich habe ein Modell User

  1. User.find(id)

Gibt eine Zeile zurück, in der Primärschlüssel = ID ist. Der Rückgabetyp ist UserObjekt.

  1. User.find_by(email:"abc@xyz.com")

Gibt in diesem Fall die erste Zeile mit übereinstimmendem Attribut oder E-Mail zurück. Der Rückgabetyp ist wieder UserObjekt.

Hinweis: - User.find_by(email: "abc@xyz.com")ähneltUser.find_by_email("abc@xyz.com")

  1. User.where(project_id:1)

Gibt alle Benutzer in der Benutzertabelle zurück, bei denen das Attribut übereinstimmt.

Hier wird der Rückgabetyp ActiveRecord::RelationObjekt sein. ActiveRecord::RelationDie Klasse enthält Rubys EnumerableModul, sodass Sie das Objekt wie ein Array verwenden und darauf durchlaufen können.


0

Das Beste an der Arbeit mit Open Source-Technologien ist, dass Sie deren Länge und Breite überprüfen können. Kasse diesen Link

find_by ~> Findet den ersten Datensatz, der den angegebenen Bedingungen entspricht. Es gibt keine implizite Bestellung. Wenn die Bestellung wichtig ist, sollten Sie sie selbst angeben. Wenn kein Datensatz gefunden wird, wird null zurückgegeben.

find ~> Findet den ersten Datensatz, der den angegebenen Bedingungen entspricht. Wenn jedoch kein Datensatz gefunden wird, wird eine Ausnahme ausgelöst, die jedoch absichtlich ausgeführt wird.

Schauen Sie sich den obigen Link an, er enthält alle Erklärungen und Anwendungsfälle für die folgenden beiden Funktionen.


-5

Ich werde persönlich empfehlen, zu verwenden

where(< columnname> => < columnvalue>)

1
Dies kann die Frage beantworten. Versuchen Sie jedoch, die Vor- und Nachteile der Verwendung Ihres Ansatzes anstelle der akzeptierten Antwort zu beschreiben.
Vivek Kumar
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.