2016-04-26 13 views
0

Ich habe eine Ruby 2.2.2 App, die ActiveRecord als ORM (ähnlich Rails) verwendet. Ich habe zwei Tabellen, "Benutzer" und "Konten", wo "Konten" belongs_to :user haben. Für einen bestimmten Benutzer, möchte ich einfach zu eifrig Last der Inhalt der „Konten“ Tabelle in ein Ruby-Objekt (genannt user_accounts), so kann ich führen Operationen wie:Eager Laden von Datenbanktabelle mit ActiveRecord

user_accounts.find_by_product_name("nameofproduct") 

... ohne die find_by_product_name Verfahren eine Durchführung SQL-Abfrage Ich möchte einfach alle Einträge aus der Tabelle "accounts" (die zu einem bestimmten Benutzer gehören) in ein Ruby-Objekt laden, damit ich die Anzahl der SQL-Abfragen minimieren kann.

Egal wie viel Dokumentation ich lese, ich kann nicht herausfinden, wie man das richtig macht. Ist das möglich? Wenn das so ist, wie?

Antwort

2

Wenn Sie nicht möchten, dass das ORM die Datenbank erneut abfragt, dann ist es besser, die Methode select zu verwenden, die vom Enumerable Mix hinzugefügt wurde. Denn wenn Sie versuchen, die find_by_* Methoden zu verwenden, denke ich, es wird immer eine andere Abfrage senden.

Hier ist ein Beispiel, wie es erreicht werden könnte.

# The accounts association will be loaded and cached the first time 
@user.accounts.select { |account| account.name == "nameofproduct" } 

# The next time, it is already loaded and will select from the previously loaded records 
@user.accounts.select { |account| account.name == "nameofanotherproduct" } 
+0

Das scheint gut zu funktionieren, danke. Eine letzte Frage: Wenn ich einen Datensatz manuell an dieses Array anhängen wollte, wäre das möglich? Also sag ich eifrig geladen die user.accounts, und ich möchte sowohl A) einen Datensatz in der tatsächlichen DB und B) fügen Sie diesen Datensatz an die user.accounts eifrig geladenen Array, ohne die gesamte Tabelle neu laden, ist das möglich ? – JimboTwice

+0

Ja, ich denke nicht, dass das ein Problem sein sollte. Wenn Sie den neuen Datensatz mit "@ user.accounts.build" oder "@ user.accounts.create" zur Datenbank hinzufügen, wird der hinzugefügte Datensatz an die zwischengespeicherten Datensätze angehängt, ohne sie alle erneut zu laden. – DanneManne

+0

Super, danke. Wir haben noch eine letzte Frage dazu: Ist es möglich, einen einzelnen Datensatz aus der Benutzertabelle zu laden und eager_load Konten für diesen einzelnen Benutzer? Wir können nicht bestimmen, wie wir das tun sollen: Wenn wir User.find_by_email ("[email protected]"), können wir nicht scheinen .eager_load zu nutzen. Ist es möglich, einen einzelnen Eintrag aus der Benutzertabelle zu laden und die Rechnungstabelle für diesen Eintrag zu laden? – JimboTwice

1

Ich würde speichern, dass in einem hash Konten anstelle ein array, weil Lookups in einem Hash viel schneller ist (in O(1)) als in einem Array, das nur O(n) ermöglicht.

group_by hilft Ihnen beim Aufbau dieses Hash.

# assuming that @user.accounts returns all accounts 
user_accounts = @user.accounts.group_by(&:name) 

# querying the hash. use `first` to receive the first matching 
# account (even if there is only one) 
user_accounts['nameofproduct'].first 
+0

Vielen Dank.Wenn ich das ausführe, erhalte ich "falsche Anzahl von Argumenten (1 für 0). Wenn ich das täte, wäre ich in der Lage, einen Hash zu erstellen, der alle Spalten in der Kontentabelle oder nur einen enthält (wie: name)? – JimboTwice

+0

Es tut mir leid, ich vermisste ein '&' in der Zeile mit der 'group_by'. Bitte sehen Sie meine aktualisierte Antwort. Ein Hash benötigt einen Schlüssel, daher ist es nicht möglich, durch mehrere Hashes Hash In diesem Fall. – spickermann

Verwandte Themen