find () mit nil, wenn keine Datensätze vorhanden sind

95

In meinem aktuellen Rails-Programm, wenn ich so etwas benutze

 user = User.find(10)

Wenn es keinen Benutzer mit ID = 10 gibt, habe ich eine Ausnahme wie:

ActiveRecord::RecordNotFound: Couldn't find User with ID=10

Kann ich Null bekommen, anstatt eine Ausnahme auszulösen, wenn ich so etwas mache wie:

unless user = Challenge.find(10)
  puts "some error msg"         
end

Ich möchte nur Null bekommen, wenn es keine Aufzeichnungen gibt, und ich möchte nicht Start / Rettung verwenden

Vielen Dank

Gl
quelle

Antworten:

170

Ja, mach einfach:

Challenge.find_by_id(10)

Für Schienen 4 und 5:

Challenge.find_by(id: 10)
apneadiving
quelle
11
seltsam! Ich hätte nie gedacht, dass die .find_by_*Null zurückkehren würden und die .findnicht.
Ddavison
Dies hat sich in Schienen 4 geändert. In dieser Antwort auf stackoverflow.com/a/26885027/1438478 erfahren Sie, wie Sie einen Artikel anhand eines bestimmten Attributs finden.
Fralcon
Ich habe ein seltsames Problem mit Rails 4.2 gefunden, bei dem beim Übergeben eines Hashs als 'x' Something.find_by(id: x)eine SQL-Anweisung mit allen Attribut / Wert-Paaren des Hashs als Teil der WHERE-Klausel erstellt wird. Sieht für mich wie ein Rails-Bug aus.
Tilo
Rails (3, 4 oder 5) generiert dynamische find_by_...Finder für jedes Attribut, das ein Modell enthält :id. Sollte also Challenge.find_by_id(10)unabhängig von der Rails-Version funktionieren.
Arta
Wie von @MohamedIbrahim unten angegeben, können Sie auch tun:Challenge.find(10) rescue nil
Hallgeir Wilhelmsen
31

In Rails 4 wurden dynamische Finder - wie find_by_idsie in der akzeptierten Antwort verwendet wurden - nicht mehr unterstützt.

In Zukunft sollten Sie die neue Syntax verwenden:

Challenge.find_by id: 10
hattila91
quelle
4
Für den Fall, dass jemand wie ich verwirrt ist: Challenge.find_by(id: 10)ist die andere Art, dies zu schreiben
Devin Howard
14

Sie können dies ein bisschen hackisch machen, verwenden Sie einfach die ActiveRecord Query Interface.

Dies gibt null zurück, anstatt eine Ausnahme auszulösen

  User.where(:id => 10).first
Mütze
quelle
Ein Grund, dies zu verwenden, find_by_idist, dass es von Schienen 3 bis 4 tragbar ist. In Schienen 4 ist es find_by(:id => 10).
Gene
5

Warum fängst du nicht einfach die Ausnahme? Ihr Fall sieht genau so aus, für welche Ausnahmen gemacht wurde:

begin
  user = User.find(10)
rescue ActiveRecord::RecordNotFound
  puts "some error msg"
end

Wenn Sie den Fehler im Rettungsblock beheben möchten (z. B. durch Festlegen eines Platzhalterbenutzers (Nullmuster)), können Sie mit Ihrem Code unter diesem Block fortfahren. Andernfalls können Sie einfach Ihren gesamten Code für den "glücklichen Fall" in den Block zwischen "beginnen" und "retten" einfügen.

Morgler
quelle
Übrigens: Sie brauchen den begin…endBlock nicht einmal , wenn Sie bereits einen Block wie eine Controller-Methode haben. In diesem Fall ist die einzige zusätzliche Leitung, die Sie benötigen, die rescueLeitung. Viel eleganter und einfacher zu handhaben als nilmit einer ifAussage zu prüfen .
Morgler
4

Sie können dies versuchen Challenge.exists?(10)

tonymarschall
quelle
7
Es wird eine zusätzliche SQL-Anfrage sein
fl00r
Trotzdem denke ich, dass dies besser zum Testen
geeignet ist
Verwenden Sie es, wenn Sie sich nicht für den zurückgegebenen Wert interessieren, sondern nur für das Vorhandensein eines Datensatzes in DB
Filip Bartuzi
4

Für diejenigen, die mit Mongoiden zu kämpfen haben , stellt sich heraus, dass sowohl findals auch find_byMethoden Ausnahmen auslösen - unabhängig von Ihrer Rails-Version!

Es gibt eine Option ( raise_not_found_error ), die auf false gesetzt werden kann, aber wenn falsey eine findMethode ausführt, wird auch keine Ausnahme ausgelöst .

Daher ist die Lösung für mongoide Benutzer der widerliche Code:

User.where(id: 'your_id').first # argghhh
Cristiano Mendonça
quelle
Was halten Sie von der Rettungslösung von Mohamed-Ibrahim? Scheint eleganter als .where(email: params[:email]).firstfür mich.
Wylliam Judd
1
Ich rescue
Cristiano Mendonça
Ich habe die Lösung von @ morgler verwendet.
Wylliam Judd
2

genauso einfach wie:

user = User.find(10) rescue nil
mohamed-ibrahim
quelle
1
Ich würde eher genauer sagen, welcher Fehler voraussichtlich behoben wird, in diesem Fall ActiveRecord :: RecordNotFound. Wie auf diese Antwort von @morgler
luizrogeriocn
2
Ich persönlich finde das die beste Antwort. Ich sage meinem Code bereits, was zu tun ist, wenn der Benutzer nicht in gefunden wirdif user...else
Wylliam Judd
0

Sie können find_by mit dem erforderlichen Attribut (in Ihrem Fall der ID) verwenden. Dies gibt nil zurück, anstatt einen Fehler auszugeben, wenn die angegebene ID nicht gefunden wird.

user = Challenge.find_by_id(id_value)

oder Sie könnten das neue Format verwenden:

user = Challenge.find_by id: id_value

Sie können auch where verwenden, aber Sie müssen wissen, dass where eine aktive Datensatzbeziehung mit null oder mehr Datensätzen zurückgibt, die Sie zuerst verwenden müssen, um nur einen Datensatz oder null zurückzugeben, falls null Datensätze zurückgegeben werden.

user = Challenge.where(id: id_value).first
Alanoud Just
quelle