So wählen Sie ausnahmslos aus, wo ID in Array Rails ActiveRecord ist

134

Wenn ich eine Reihe von IDs habe, wie

ids = [2,3,5]

und ich trete auf

Comment.find(ids)

alles funktioniert gut. Aber wenn es eine ID gibt, die nicht existiert, bekomme ich eine Ausnahme. Dies tritt im Allgemeinen auf, wenn ich eine Liste von IDs erhalte, die mit einem Filter übereinstimmen, und dann so etwas mache

current_user.comments.find(ids)

Dieses Mal habe ich möglicherweise eine gültige Kommentar-ID, die jedoch nicht dem angegebenen Benutzer gehört, sodass sie nicht gefunden wird und ich eine Ausnahme erhalte.

Ich habe es versucht find(:all, ids), aber es werden alle Datensätze zurückgegeben.

Ich kann es jetzt nur noch tun

current_user.comments.select { |c| ids.include?(c.id) }

Aber das scheint mir eine super ineffiziente Lösung zu sein.

Gibt es eine bessere Möglichkeit, die ID im Array auszuwählen, ohne eine Ausnahme für nicht vorhandene Datensätze zu erhalten?

Jakub Arnold
quelle

Antworten:

215

Wenn nur die Ausnahme vermieden wird, über die Sie sich Sorgen machen, funktioniert die Funktionsfamilie "find_all_by .." ohne Ausnahmen.

Comment.find_all_by_id([2, 3, 5])

funktioniert auch dann, wenn einige der IDs nicht vorhanden sind. Das funktioniert in der

user.comments.find_all_by_id(potentially_nonexistent_ids)

Fall auch.

Update: Schienen 4

Comment.where(id: [2, 3, 5])
Prisma von allem
quelle
Dies ist meine bevorzugte Lösung. Sie scheint sauberer zu sein als die Route zur Ausnahmebehandlung
Sam Saffron,
5
Als weitere Erweiterung könnten Sie, falls Sie komplexe Bedingungen verketten müssen, sogar Comment.all (: Bedingungen => ["genehmigt und ID in (?)", [1,2,3]])
Omar Qureshi
14
Dies wird in Rails 4 veraltet sein: edgeguides.rubyonrails.org/…
Jonathan Lin
3
@ JonathanLin ist richtig, mjnissims Antwort sollte bevorzugt werden: stackoverflow.com/a/11457025/33226
Gavin Miller
6
Dies gibt ein Arraystatt eines zurück ActiveRecord::Relation, was einschränkt, was Sie danach damit machen können. Comment.where(id: [2, 3, 5])gibt ein zurück ActiveRecord::Relation.
Joshua Pinter
147

Update: Diese Antwort ist für Rails 4.x relevanter

Mach das:

current_user.comments.where(:id=>[123,"456","Michael Jackson"])

Die stärkere Seite dieses Ansatzes besteht darin, dass ein RelationObjekt zurückgegeben wird, dem Sie weitere .whereKlauseln, .limitKlauseln usw. hinzufügen können, was sehr hilfreich ist. Es erlaubt auch nicht existierende IDs ohne Ausnahmen.

Die neuere Ruby-Syntax wäre:

current_user.comments.where(id: [123, "456", "Michael Jackson"])
mjnissim
quelle
Vielen Dank, dass Sie die whereSyntax beim Vergleich mit einem Array bestätigt haben. Ich dachte, ich müsste das SQL möglicherweise mit einer INAnweisung codieren , aber dies sieht sauberer aus und ist ein einfacher Ersatz für das Veraltete scoped_by_id.
Mark Berry
1
Wie heißt das und wie funktioniert es? Ist es Rails Magie?! Als ein Kollege bemerkte, wie seine ‚Vergleich eine ganze Zahl mit einer Objektliste“.
atw
22

Wenn Sie mehr Kontrolle benötigen (möglicherweise müssen Sie den Tabellennamen angeben), können Sie auch Folgendes tun:

Model.joins(:another_model_table_name)
  .where('another_model_table_name.id IN (?)', your_id_array)
Jonathan Lin
quelle
Genau das, wonach ich gesucht habe. Vielen Dank!
Myxtic
Gibt es eine Möglichkeit, die Reihenfolge beizubehalten, in der your_id_arraySie die Objekte zurückerhalten?
Joshua Pinter
@JoshPinter Ich denke nicht, dass dies eine zuverlässige Methode ist, um zu erwarten, dass die Datenbank die Dinge in derselben Reihenfolge zurückgibt. Fügen Sie am Ende möglicherweise eine ORDER BY-Abfrage hinzu, um die richtige Reihenfolge zu gewährleisten.
Jonathan Lin
@ JonathanLin Danke für die Antwort Jonathan. Du hast sicherlich recht. Die Verwendung von ORDER BYfunktioniert in meiner Situation nicht, da die Reihenfolge nicht auf einem Attribut basiert. Es gibt jedoch eine Möglichkeit, dies über SQL zu tun (es ist also schnell), und jemand hat sogar ein Juwel dafür erstellt. Schauen Sie sich diese Fragen und Antworten an
Joshua Pinter
10

Jetzt sind die Methoden .find und .find_by_id in Rails 4 veraltet. Stattdessen können wir Folgendes verwenden:

Comment.where(id: [2, 3, 5])

Es wird auch dann funktionieren, wenn einige der IDs nicht vorhanden sind. Das funktioniert in der

user.comments.where(id: avoided_ids_array)

Auch zum Ausschließen von IDs

Comment.where.not(id: [2, 3, 5])
Sumit Munot
quelle
3
github.com/rails/activerecord-deprecated_finders .find- und .find_by_id-Methoden sind in Rails 4 NICHT veraltet.
Canna
0

Um zu vermeiden, dass Ausnahmen Ihre App beenden, sollten Sie diese Ausnahmen abfangen und wie gewünscht behandeln und das Verhalten für Ihre App in Situationen definieren, in denen die ID nicht gefunden wird.

begin
  current_user.comments.find(ids)
rescue
  #do something in case of exception found
end

Hier finden Sie weitere Informationen zu Ausnahmen in Ruby.

rogeriopvl
quelle
1
Ja, das löst das Problem, aber es ist keine wirklich saubere Lösung
Jakub Arnold
3
Wenn Sie eine Ausnahme abfangen möchten, sollten Sie die Ausnahme deklarieren, die Sie abfangen möchten. Andernfalls riskieren Sie, dass sie etwas abfängt, das Sie nicht erwartet haben, und ein tatsächliches Problem verbirgt.
Haegin
0

Sie können es auch in named_scope verwenden, wenn Sie dort andere Bedingungen festlegen möchten

Schließen Sie zum Beispiel ein anderes Modell ein:

named_scope 'get_by_ids', lambda {| ids | {: include => [: Kommentare] ,: Bedingungen => ["Kommentare.id IN (?)", IDs]}}

mtfk
quelle