2017-01-24 1 views
1

Ich habe Benutzer, Probleme und Versuche, die eine Join-Tabelle zwischen Benutzern und Problemen ist. Ich versuche, einen Index aller Probleme zusammen mit dem letzten Versuch des aktuellen Benutzers für jeden zu zeigen, wenn sie einen haben.Rails links Join mit Bedingungen

Ich habe vier Dinge ausprobiert, um eine linke Verbindung mit Bedingungen zu bekommen, und keine von ihnen hat funktioniert.

Der naive Ansatz ist so etwas wie ...

@problems = Problem.enabled 
@problems.each do { |prob| 
    prob.last_attempt = prob.attempts 
          .where(user_id: current_user.id) 
          .last 
end 

Dies wird alle Probleme und die Versuche, ich will, aber ist N + 1 Abfragen. So ...

@problems = Problem.enabled 
        .includes(:attempts) 

Dies verbinden die linken (oder die entsprechenden zwei Abfragen), um alle Probleme bekommen, sondern auch alle Versuche, nicht nur die für den aktuellen Benutzer. So ...

@problems = Problem.enabled 
        .includes(:attempts) 
        .where(attempts: {user_id: current_user.id}) 

Dies wird nur diejenigen Probleme, die der aktuelle Benutzer bereits versucht hat. So ...

//problem.rb 
has_many :user_attempts, 
     -> (user) { where(user_id: user.id) }, 
     class_name: 'Attempt' 

//problem_controller.index 
@problems = Problem.enabled 
        .includes(:user_attempts, current_user) 

Und das gibt eine Fehlermeldung aus Schienen sagen verbindet sich mit Beispiel Argumente werden nicht unterstützt.

So bin ich stecken. Was ist der beste Weg, dies zu tun? Ist Arel das richtige Werkzeug? Kann ich aktive Aufzeichnungen überspringen und nur einen JSON-Blob zurückbekommen? Bin ich nur dumm?

Diese Frage ist völlig ähnlich zu this one, aber ich würde ein Argument für den verbundenen Bereich benötigen, die nicht unterstützt wird. Und ich hoffe, dass Schienen in den letzten paar Jahren etwas hinzugefügt haben.

Vielen Dank für Ihre Hilfe.

Antwort

0

Die Art, wie ich das löste, war die Verwendung von Raw SQL. Es ist hässlich und ein Sicherheitsrisiko, aber ich habe es nicht besser gefunden.

results = Problem.connection.exec_query(%(
    SELECT * 
    FROM problems 
    LEFT JOIN (
     SELECT * 
    //etc. 
    ) 
)) 

Und dann das Ergebnis-Array im Speicher manipulieren.