Ich habe eine Reihe von Objekten, nennen wir es ein Indicator
. Ich möchte Indicator-Klassenmethoden (die der def self.subjects
Sorte, Bereiche usw.) für dieses Array ausführen . Die einzige Möglichkeit, Klassenmethoden für eine Gruppe von Objekten auszuführen, besteht darin, dass sie eine ActiveRecord :: Relation sind. Am Ende greife ich auf das Hinzufügen einer to_indicators
Methode zurück Array
.
def to_indicators
# TODO: Make this less terrible.
Indicator.where id: self.pluck(:id)
end
Manchmal verkette ich einige dieser Bereiche, um die Ergebnisse innerhalb der Klassenmethoden herauszufiltern. Obwohl ich eine Methode für eine ActiveRecord :: Relation aufrufe, weiß ich nicht, wie ich auf dieses Objekt zugreifen soll. Ich kann nur durch zum Inhalt kommen all
. Ist all
aber ein Array. Dann muss ich dieses Array in eine ActiveRecord :: Relation konvertieren. Dies ist beispielsweise Teil einer der folgenden Methoden:
all.to_indicators.applicable_for_bank(id).each do |indicator|
total += indicator.residual_risk_for(id)
indicator_count += 1 if indicator.completed_by?(id)
end
Ich denke, dies verdichtet sich auf zwei Fragen.
- Wie kann ich ein Array von Objekten in eine ActiveRecord :: Relation konvertieren? Am besten ohne
where
jedes Mal. def self.subjects
Wie greife ich beim Ausführen einer Typmethode auf einer ActiveRecord :: Relation auf dieses ActiveRecord :: Relation-Objekt selbst zu?
Vielen Dank. Wenn ich etwas klarstellen muss, lass es mich wissen.
quelle
.all
, verwenden Sie es einfach.scoped
wie in Andrew Marshalls Antwort angegeben (obwohl es in Schienen 4 funktioniert.all
). Wenn Sie feststellen, dass Sie ein Array in eine Beziehung verwandeln müssen, sind Sie irgendwo falsch gelaufen ...Antworten:
Sie können ein Array nicht in eine ActiveRecord :: Relation konvertieren, da eine Relation nur ein Builder für eine SQL-Abfrage ist und ihre Methoden nicht mit tatsächlichen Daten arbeiten.
Wenn Sie jedoch eine Beziehung wünschen, dann:
Rufen Sie für ActiveRecord 3.x nicht auf
all
und rufen Sie stattdessen auf. Dadurchscoped
wird eine Relation zurückgegeben, die dieselben Datensätze darstellt,all
die Sie in einem Array erhalten würden.Rufen Sie für ActiveRecord 4.x einfach auf
all
, wodurch eine Beziehung zurückgegeben wird.Wenn die Methode für ein Relation-Objekt aufgerufen wird,
self
ist dies die Relation (im Gegensatz zu der Modellklasse, in der sie definiert ist).quelle
class User; def self.somewhere; where(location: "somewhere"); end; end
, dannUser.limit(5).somewhere
Sie können ein Array von Objekten
arr
wie folgt in eine ActiveRecord :: Relation konvertieren (vorausgesetzt, Sie wissen, welche Klasse die Objekte sind, was Sie wahrscheinlich tun).Sie müssen es jedoch verwenden
where
, es ist ein nützliches Werkzeug, das Sie nicht ungern verwenden sollten. Und jetzt haben Sie einen Einzeiler, der ein Array in eine Beziehung konvertiert.map(&:id)
verwandelt Ihr Array von Objekten in ein Array, das nur deren IDs enthält. Wenn Sie ein Array an eine where-Klausel übergeben, wird eine SQL-Anweisung generiertIN
, die ungefähr so aussieht:Denken Sie daran, dass die Reihenfolge des Arrays verloren geht. Da Ihr Ziel jedoch nur darin besteht, eine Klassenmethode für die Sammlung dieser Objekte auszuführen , gehe ich davon aus, dass dies kein Problem darstellt.
quelle
where(id: arr.map(&:id))
? Genau genommen konvertiert dies das Array nicht in eine Beziehung, sondern ruft stattdessen neue Instanzen der Objekte (sobald die Beziehung realisiert ist) mit den IDs ab, die möglicherweise andere Attributwerte als die bereits im Speicher befindlichen Instanzen im Array haben.Nun, in meinem Fall, ich brauche , um ein Array von Objekten zu Active Umwandlung :: Relation sowie Sortier- sie mit einer bestimmten Spalte (id zum Beispiel). Da ich MySQL verwende, kann die Feldfunktion hilfreich sein.
Das SQL sieht aus wie:
MySQL-Feldfunktion
quelle
ActiveRecord::Relation
bindet eine Datenbankabfrage, die Daten aus der Datenbank abruft.Nehmen wir an, wir haben ein Array mit Objekten derselben Klasse. Mit welcher Abfrage sollen wir sie dann binden?
Wenn ich renne,
Hier oben,
users
RückkehrRelation
Objekt , sondern bindet Datenbankabfrage dahinter und man kann es sehen,Es ist daher nicht möglich,
ActiveRecord::Relation
von einem Array von Objekten zurückzukehren, das von der SQL-Abfrage unabhängig ist.quelle
Erstens ist dies KEINE Silberkugel. Aufgrund meiner Erfahrung stellte ich fest, dass die Konvertierung in eine Beziehung manchmal einfacher ist als Alternativen. Ich versuche, diesen Ansatz sehr sparsam und nur in Fällen anzuwenden, in denen die Alternative komplexer wäre.
Davon abgesehen ist meine Lösung, ich habe den
Array
Unterricht erweitertEin Anwendungsbeispiel wäre
array.to_activerecord_relation.update_all(status: 'finished')
. Wo verwende ich es jetzt?Manchmal müssen Sie
ActiveRecord::Relation
beispielsweise nicht abgeschlossene Elemente herausfiltern. In diesen Fällen ist es am besten, den Umfang zu verwenden,elements.not_finished
und Sie würden ihn trotzdem behaltenActiveRecord::Relation
.Aber manchmal ist dieser Zustand komplexer. Nehmen Sie alle Elemente heraus, die noch nicht fertig sind und die in den letzten 4 Wochen hergestellt und inspiziert wurden. Um das Erstellen neuer Bereiche zu vermeiden, können Sie in ein Array filtern und dann zurück konvertieren. Denken Sie daran, dass Sie immer noch eine Abfrage an DB durchführen, schnell, da diese nach
id
einer Abfrage sucht .quelle