Ihre Frage ist wahrscheinlich ohne Schnittmenge lösbar, etwa so:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Das Folgende ist jedoch ein allgemeiner Ansatz, den ich zum Erstellen von Abfragen wie Schnittmengen in ActiveRecord verwende:
class Service < ActiveRecord::Base
belongs_to :person
def self.with_types(*types)
where(service_type: types)
end
end
class City < ActiveRecord::Base
has_and_belongs_to_many :services
has_many :people, inverse_of: :city
end
class Person < ActiveRecord::Base
belongs_to :city, inverse_of: :people
def self.with_cities(cities)
where(city_id: cities)
end
def self.with_all_service_types(*types)
types.map { |t|
joins(:services).merge(Service.with_types t).select(:id)
}.reduce(scoped) { |scope, subquery|
scope.where(id: subquery)
}
end
end
Person.with_all_service_types(1, 2)
Person.with_all_service_types(1, 2).with_cities(City.where(name: 'Gold Coast'))
Es generiert SQL der Form:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Sie können mit dem obigen Ansatz so viele Unterabfragen wie erforderlich erstellen, basierend auf beliebigen Bedingungen/Verknüpfungen usw., solange jede Unterabfrage die ID einer übereinstimmenden Person in ihrer Ergebnismenge zurückgibt.
Jede Unterabfrage-Ergebnismenge wird UND-verknüpft, wodurch die übereinstimmende Menge auf die Schnittmenge aller Unterabfragen beschränkt wird.
AKTUALISIEREN
Für diejenigen, die AR4 verwenden, wobei scoped
entfernt wurde, liefert meine andere Antwort einen semantisch äquivalenten scoped
polyfil welche all
ist kein äquivalenter Ersatz für trotz allem, was die AR-Dokumentation vorschlägt. Antworten Sie hier:Mit Rails 4 ist Model.scoped veraltet, aber Model.all kann es nicht ersetzen