La tua domanda è probabilmente risolvibile senza intersezione, qualcosa del tipo:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Tuttavia, il seguente è un approccio generale che utilizzo per costruire query simili a intersezioni in 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'))
Genererà SQL del modulo:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Puoi creare tutte le sottoquery necessarie con l'approccio sopra in base a qualsiasi condizione/join, ecc., purché ogni sottoquery restituisca l'id di una persona corrispondente nel suo set di risultati.
Ciascun set di risultati di sottoquery verrà sottoposto a AND insieme, limitando così il set di corrispondenza all'intersezione di tutte le sottoquery.
AGGIORNAMENTO
Per coloro che utilizzano AR4 con scoped
è stato rimosso, l'altra mia risposta fornisce un scoped
semanticamente equivalente polyfil che all
non è un sostituto equivalente nonostante ciò che suggerisce la documentazione AR. Rispondi qui:Con Rails 4, Model.scoped è deprecato ma Model.all non può sostituirlo