0

Mit Rails 4, und angesichts der folgenden Modelle:Suche Datensätze ohne has_many: durch Aufzeichnung Kriterien

class Draft < ActiveRecord::Base 
    has_many :drafters 
    has_many :users, through: :drafters 
end 

class Drafter < ActiveRecord::Base 
    belongs_to :draft 
    belongs_to :user 
end 

class User < ActiveRecord::Base 
    has_many :drafters 
    has_many :drafts, through: :drafters 
end 

Wie kann ich alle Entwürfe abrufen, die current_user nicht mit dem User-Instanz zugeordnet? Das heißt, alle Entwürfe d, für die es keinen Drafter zu d und current_user gibt.

Ich habe Squeel verfügbar, wenn es hilft.

Antwort

0

ich gefunden habe, eine Antwort (mit squeel) auf der Grundlage der folgenden verschachtelten Abfrage:

SELECT "drafts"."id" FROM "drafts" 
    WHERE "drafts"."id" NOT IN 
     (SELECT "drafters"."draft_id" FROM "drafters" 
      WHERE (("drafters"."draft_id" = "drafters"."id" 
        AND "drafters"."user_id" = 2))) 

Das ist umwandelbar in die Rails + Quietsche Abfrage:

Draft.where{ id.not_in(Drafter.select(:draft_id).where{ 
     (draft_id == drafts.id) & (user_id == omit_user_id)})} 
1

Sie können es mit includes implementieren:

Draft.includes(:drafters) 
    .where('(drafters.user_id <> ? or drafters.user_id is null)', current_user.id}) 
    .references(:drafters) 
+0

Dies funktioniert nicht ganz. Erstens findet es keine Entwürfe, die überhaupt keinen Zeichner haben. Zweitens, die Verwendung von es produziert eine Vernachlässigung: 'DEPRECATION WARNING: Es sieht so aus, als ob Sie eifrig Tabellen laden (eine von: Entwürfen, Verfasser), die in einer Zeichenfolge SQL-Schnipsel verwiesen werden. - Volltext [hier] (https: //gist.githubusercontent.com/asilano/823cb76f7b29af02f2ef41d24b8bc7d3/raw/3bd4470b4eb26a45bc21a4e2b9ba92a82bd31a95/gistfile1.txt) – Chowlett

+0

@Chowlett: Aktualisiert. 'references' entfernt die Verwarnungswarnung (d. h. erzwingt' left join'), während 'is null'-Prüfung Entwürfe ohne Zeichner erlaubt. – potashin

+0

Uh, wow. Das ist viel hässlicher, als ich es erwartet hatte. Warum funktioniert es? Das SQL, das erzeugt wird, ist ein LEFT OUTER JOIN auf Draft <-> Drafter, also sollte Reihen aufstellen, in denen die Drafter Seite abwesend ist. Warum brauche ich 'drafters.user_id ist null ', um die Fälle zu erfassen, in denen keine Drafter-Zeile mit' drafter.draft_id' übereinstimmt? – Chowlett

0
Draft.includes(:drafters).where(:drafters => { :draft_id => nil }) 

überhaupt alle Entwürfe ohne drafter zurück.

Draft.includes(:drafters).where.not(:drafter => { user_id => current_user.od }) 

gibt alle Entwürfe zurück, die nicht zu current_user gehören.

Weitere Details finden Sie unter the difference between outer an inner join.

1

Mit squeel können Sie tun:

Draft.joins{drafters.outer}.where{(drafters.user_id != current_user.id) | (drafters.user_id.eq nil)} 

, die generieren:

SELECT "drafts".* FROM "drafts" LEFT OUTER JOIN "drafters" ON "drafters"."draft_id" = "drafts"."id" WHERE ("drafters"."user_id" != 1 OR "drafters"."user_id" IS NULL) 
+0

Ich versuchte dieses, aber am Ende fand es mehrere Entwürfe zurück, wo es mehr als einen non-current_user Drafters gab. Die Methode 'includes' scheint der einzige Weg zu sein. – Chowlett