Dit spørgsmål kan sandsynligvis løses uden skæringspunkter, sådan som:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Men det følgende er en generel tilgang, jeg bruger til at konstruere kryds-lignende forespørgsler 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 vil generere SQL af formen:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Du kan oprette så mange underforespørgsler, som det kræves med ovenstående tilgang baseret på alle betingelser/sammenføjninger osv., så længe hver underforespørgsel returnerer id'et for en matchende person i sit resultatsæt.
Hvert underforespørgselsresultatsæt vil blive OG'et sammen, hvilket begrænser det matchende sæt til skæringspunktet mellem alle underforespørgslerne.
OPDATERING
For dem, der bruger AR4, hvor scoped
blev fjernet, giver mit andet svar en semantisk ækvivalent scoped
polyfil som all
er ikke en tilsvarende erstatning for på trods af, hvad AR-dokumentationen antyder. Svar her:Med Rails 4 er Model.scoped forældet, men Model.all kan ikke erstatte det