2016-03-31 5 views
1

Ich habe ein spezifisches Beispiel, aber die allgemeine Frage ist: Was ist der optimale Weg, um Datensätze abzurufen, wenn Sie ein Array von Filterwerten haben, die übereinstimmen?Ruby on Rails optimale Suche mit Array von Filterwerten?

Sagen, ich habe User und Post Datensätze, in denen Benutzer has_many :posts

und ich haben ein Relationship Modell, das wie folgt aussieht:

class Relationship < ActiveRecord::Base 
    belongs_to :follower, class_name: "User" 
    belongs_to :followed, class_name: "User" 
    validates :follower_id, presence: true 
    validates :followed_id, presence: true 
end 

ich eine Funktion schreiben will, die in chronologischer Reihenfolge zurückgibt Beiträge von Ihrem folgenden bestellt "Following" - also alle Posts von Nutzern, denen die von Ihnen bearbeiteten Nutzer folgen, ausgenommen Duplikate und Posts von Nutzern, denen Sie folgen.

Meine Lösung ist es, zuerst ein Array aller Nutzer von Interesse zu kompilieren:

users = [] 
@user.following.each do |f| 
    f.following.each do |ff| 
    users << ff 
    end 
end 

# dedupe 
users = users.uniq 

#remove self and following 
users.delete(@user) 
@user.following.each do |f| 
    users.delete(f) 
end 

dann ihre Beiträge zusammenstellen und bestellen:

posts = [] 
users.each do |u| 
    posts += u.posts 
end 
posts.sort_by!{|x| x[:created_at]}.reverse! 

Ich denke, es gibt einen besseren Weg, dies zu tun mit Active Record-Funktionen, aber ich kann nicht herausfinden, wie sie mit einem Array arbeiten. Zum Beispiel, wenn ich id Werte anstelle der vollen Modelle eine Reihe von Benutzer kompilieren, und versuchen Sie diesen Code ausführen, um die Post-Array zu erhalten:

posts = Post.where(
    user_id: user_ids 
).order('created_at DESC').limit(21) 

es gibt ein leeres Array. Gibt es eine bessere Möglichkeit, mit einem Array von Filterwerten als mit meiner aktuellen Lösung zu suchen?

Update: zusätzliche modale Code:

class Post < ActiveRecord::Base 
    belongs_to :user 
    ... 

User.rb

class User < ActiveRecord::Base 
    has_many :photos 
    has_many :active_relationships, class_name: "Relationship", 
           foreign_key: "follower_id", 
           dependent: :destroy 
    has_many :passive_relationships, class_name: "Relationship", 
           foreign_key: "followed_id", 
           dependent: :destroy 
    has_many :following, through: :active_relationships, source: :followed 
    has_many :followers, through: :passive_relationships, source: :follower 
    ... 
+0

Hat ein 'Benutzer'' has_many: followings, wie:: follower, class_name: 'Relationship''? – Aetherus

+0

Ja, ich aktualisierte mit mehr modalem Code – Cbas

+0

Wenn Sie über ActiveRecord-Sammlungen iterieren, verwenden Sie 'find_each' anstelle von' each'. 'find_each' lädt Datensätze aus der Sammlung in Stapeln und nicht auf einmal, was offensichtlich sicherer für Ihre Speicherauslastung ist. –

Antwort

1

Ihre Idee benutzerkennungen zu verwenden, ist ein guter. Wenn diese Abfrage ein leeres Array zurückgegeben hat, haben Sie dann überprüft, ob die user_ids die erwarteten sind? Für den Code müssen Sie in Enumerable#map und #flat_map suchen. Sie sind eingebaute Ruby-Methoden, um das zu erreichen, was Sie mit den #each-Schleifen erreichen wollen. Code könnte so etwas wie reduzieren:

user_ids = user.followings.flat_map { |following| following.following_id } 
user_ids.uniq! 
user_ids -= [user.id, user.following_ids].flatten 
Post.where(user_id: user_ids).order(id: :desc).limit(21) 

Hinweis: Da created_at sollte id Schöpfungsordnung folgen, Ich würde auf id Benutzer basiert, anstatt created_at da sollte es einen Index haben.