Din fråga är förmodligen lösbar utan skärningspunkt, ungefär som:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Men följande är ett allmänt tillvägagångssätt som jag använder för att konstruera korsningar som frågor i ActiveRecord:
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'))
Det kommer att generera SQL i formen:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Du kan skapa så många underfrågor som krävs med ovanstående tillvägagångssätt baserat på alla villkor/kopplingar etc så länge som varje underfråga returnerar id:t för en matchande person i dess resultatuppsättning.
Varje delfrågeresultatuppsättning kommer att OCH sammanföras, vilket begränsar matchningsuppsättningen till skärningspunkten mellan alla underfrågor.
UPPDATERA
För de som använder AR4 där scoped
togs bort, ger mitt andra svar en semantiskt likvärdig scoped
polyfil som all
är inte en likvärdig ersättning för trots vad AR-dokumentationen antyder. Svara här:Med Rails 4 är Model.scoped utfasad men Model.all kan inte ersätta den