Su pregunta probablemente se pueda resolver sin intersección, algo así como:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Sin embargo, el siguiente es un enfoque general que uso para construir intersecciones como consultas en 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'))
Generará SQL de la forma:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Puede crear tantas subconsultas como sea necesario con el enfoque anterior en función de cualquier condición/unión, etc., siempre que cada subconsulta devuelva la identificación de una persona coincidente en su conjunto de resultados.
Cada conjunto de resultados de subconsulta se combinará con AND, restringiendo así el conjunto coincidente a la intersección de todas las subconsultas.
ACTUALIZAR
Para aquellos que usan AR4 donde scoped
fue eliminado, mi otra respuesta proporciona un scoped
semánticamente equivalente polyfil que all
no es un reemplazo equivalente a pesar de lo que sugiere la documentación AR. Responda aquí:Con Rails 4, Model.scoped está obsoleto pero Model.all no puede reemplazarlo