2017-05-02 1 views
1

Ich habe zwei Modelle:Wie Active bauen Abfrage mit bestimmten Spalten verbinden

class Friend < ApplicationRecord 
    belongs_to :user 
end 

class User < ApplicationRecord 
    has_many :friends 
end 

Das Schema der Modelle ist wie folgt:

create_table "friends" do |t| 
    t.integer "user_id" 
    t.integer "friends_max" 
    t.integer "friends_count",       null: false 
    t.datetime "created_at",        null: false 
    t.datetime "updated_at",        null: false 
end 

create_table "users" do |t| 
    t.string "name" 
    t.string "email" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

Ich habe 3 user Aufzeichnungen Unter der Annahme, dass die folgenden :

[id: 1, name: "John", email: "[email protected]", created_at: "2017-03-29 02:33:41", updated_at: "2017-03-29 02:33:11"] 
[id: 2, name: "Rob", email: "[email protected]", created_at: "2017-03-21 02:33:41", updated_at: "2017-03-29 02:33:33"] 
[id: 3, name: "Tommy", email: "[email protected]", created_at: "2017-02-29 02:33:41", updated_at: "2017-03-29 02:33:32"] 

und 6 friends Datensätze:

012.351.
[id: 52, user_id: 1, friends_max: 5, friends_count: 2, created_at: "2017-05-01 21:10:37", updated_at: "2017-05-01 21:10:37"] 
[id: 53, user_id: 1, friends_max: 5, friends_count: 2, created_at: "2017-05-01 21:10:37", updated_at: "2017-05-01 21:10:37"] 
[id: 54, user_id: 2, friends_max: 5, friends_count: 3, created_at: "2017-05-01 21:10:37", updated_at: "2017-05-01 21:10:37"] 
[id: 55, user_id: 2, friends_max: 2, friends_count: 2, created_at: "2017-05-01 21:10:37", updated_at: "2017-05-01 21:10:37"] 
[id: 56, user_id: 2, friends_max: 4, friends_count: 2, created_at: "2017-05-01 21:10:37", updated_at: "2017-05-01 21:10:37"] 
[id: 57, user_id: 3, friends_max: 1, friends_count: 0, created_at: "2017-05-01 21:10:37", updated_at: "2017-05-01 21:10:37"] 

Was ich will mich zu tun ist, um all friends Aufzeichnungen in den letzten 30 Tagen zu finden, zusammen mit der zugehörigen E-Mail von den user_id Spalt und speichern sie in einer Hash. Am Ende sollten 6 verschiedene Hashes aufgebaut sein (aus den 6 friends Records).

Ich glaube, ich etwas schrieb, dass dies erreicht, aber es ist nicht zu recht:

hold = [] 

User.includes(:friends).where(friends: {created_at: 30.days.ago..Time.now}).each do |i| 
    i.friends.each do |o| 
    hold << { 
     friends_count: o.friends_count, 
     friends_max: o.friends_max, 
     email: i.email 
    } 
    end 
end 

puts hold 

Ein Beispiel Ergebnis für eine friends Datensatz (ID: 52) sein sollte:

{:friends_count=>2, :friends_max=>5, :email=>"[email protected]"} 

Aber Natürlich werden alle 6 der friends Datensätze zurückgegeben. Kennt jemand einen saubereren Weg, dies zu tun? Vielen Dank.

Antwort

1

Erstens kann Ihre Methode nicht ganz tun, was Sie denken, es tut. Sie führen eine Abfrage aus, die eine ActiveRecord-Beziehung zurückgibt, die auf alle Benutzer verweist, die über einen Freund verfügen, der in den letzten 30 Tagen erstellt wurde. Als nächstes iterieren Sie über diese Benutzer und für jeden Benutzer durchlaufen Sie über alle der Freunde des Benutzers - nicht nur die Freunde, die in den letzten 30 Tagen erstellt wurden.

Ich glaube nicht, dass Sie Ihre Abfrage durch die Suche nach Benutzern starten möchten. Sie suchen wirklich nach Freunden, und nebenbei möchten Sie die zugehörige Benutzer-E-Mail einfügen.

Ich würde damit beginnen, ein paar Bereiche zu erstellen, die in Ihrer Abfrage verwendet werden. Diese werden mit anderen Methoden in Ihrem Code zur Verfügung und können auf jedem vorhandenen Umfang der Freunde aufgerufen werden:

class Friend < ApplicationRecord 
    belongs_to :user 
    scope :recently_created, -> { where(created_at: 30.days.ago..Time.now) } 
    scope :with_user_email, -> { joins(:user).select('friends.*, users.email') } 
end 

Jetzt können Sie bereinigen Ihre Methode unter Verwendung dieser Bereiche und Rubys Einbau-Array-Methoden. Während wir schon dabei sind, sollten Sie diese Namen aus einem Buchstaben entfernen und sinnvolle Namen verwenden:

Friend.recently_created.with_user_email.map do |friend| 
    friend.attributes.slice('friends_max', 'friends_count', 'email') 
end 
1

können Sie den folgenden Code verwenden

User.joins(:friends) 
    .where("friends.created_at":(30.days.ago..Time.now)) 
    .select("users.email, friends.friends_max, friends.friends_count") 
    .collect{|x| x.attributes.except('id') } 
+0

Fantastisch, das ist genau das, wonach ich gesucht habe. Ich bin mir nicht sicher, wie ich das anfangs übersehen habe. Vielen Dank. Ich nehme an, ich habe die Lösung etwas überholt. –