2017-06-29 5 views
0

Ich möchte Benutzern meiner Anwendung die Möglichkeit geben, unerwünschte Micropros von ihren Microposts zu entfernen. Standardmässig ist der microposts' Feed der eigenen microposts des Benutzers gemacht und die microposts von gefolgt Benutzer:Subtrahieren Sie zwei ActiveRecord :: Relation-Objekte

def feed 
    following_ids = "SELECT followed_id FROM relationships 
        WHERE follower_id = :user_id" 
    Micropost.where("user_id IN (#{following_ids}) 
        OR user_id = :user_id", user_id: id) 
end 

Ich habe ein Quarantine Modell, bei dem Benutzer und unerwünschte microposts zugeordnet sind. Dann suchte ich nach einer ActiveRecord::Relation Methode, die mir erlaubt, aus den obigen where folgenden where zu subtrahieren:

microposts_ids = "SELECT micropost_id FROM quarantines 
        WHERE user_id = :user_id" 

Micropost.where("micropost_id IN (#{microposts_ids})", user_id: id) 

ich keine Methode gefunden, die die - Arrays Betreiber entsprechen. Jedoch fand ich Methode merge in einem Stackoverflow Frage: Combine two ActiveRecord::Relation objects, dass, soweit ich verstanden, mich zu Kette erlauben würde, die wheres wie folgt:

Micropost.where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: id).merge(Micropost.where.not("micropost_id IN (#{microposts_ids})", user_id: id)) 

Der Unterschied ist, dass ich die zweite where in eine where.not geändert.
Das Problem mit dieser Lösung ist, dass die where.not alle MicroPosts laden würde, die nicht unter Quarantäne gestellt werden, was eine schwerere Aufgabe für die Datenbank ist, als nur die Quarantäne-Mikroposten zu laden. Gibt es eine alternative Lösung für die merge-Methode, z. B. eine Methode, die die Quarantäne-Mikroposten vom ursprünglichen Feed subtrahiert?

Antwort

1

Für ein bestimmtes user

microsposts_not_to_show = Micropost.joins(:quarantines).where("quarantines.user_id" => user.id) 
all_microposts = Micropost.where("user_id" => user.id) + Micropost.joins(:user => : relationships).where("relationships.follower_id" => user.id) 
microposts_to_show = all_microposts - microposts_not_to_show 
+0

Ich bin mir nicht sicher, ob die Definition von 'micropros_not_to_show' korrekt ist: Es sollte ein Micropost-Objekt und kein Quarantine-Objekt zurückgeben: Das wher-Argument enthält ein Quarantäne-Objekt. – Asarluhi

+0

Wir schließen uns den Tabellen an. Es wird kein Quarantine-Objekt angezeigt, bis es explizit mit der select-Methode angegeben wird. – moyinho20

+0

Ich erhalte folgende Warnung: 'ActiveRecord :: StatementInvalid: PG :: UndefinedColumn: FEHLER: Spalte Quarantänen.User_ID existiert nicht'. – Asarluhi

0

Für Rails 5 es aussehen könnte:

class User < ApplicationRecord 
    has_many :relationships 
    # ... 
    def feed 
    Micropost 
     .where(user_id: relationships.select(:followed_id)) 
     .or(Micropost.where(user_id: id)) 
     .where.not(id: Quarantine.select(:micropost_id).where(user_id: id)) 
    end 
end 

Die feed kehrt relation, die erzeugen ony eine DB Anfrage und mit zusätzlicher Filterung, Bestellung verkettet werden kann - was auch immer du brauchst.