Sua pergunta provavelmente é solucionável sem interseção, algo como:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
No entanto, o seguinte é uma abordagem geral que uso para construir consultas como interseções no 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'))
Ele irá gerar SQL da forma:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Você pode criar quantas subconsultas forem necessárias com a abordagem acima com base em quaisquer condições/junções etc., desde que cada subconsulta retorne o id de uma pessoa correspondente em seu conjunto de resultados.
Cada conjunto de resultados de subconsulta será combinado com AND, restringindo assim o conjunto correspondente à interseção de todas as subconsultas.
ATUALIZAÇÃO
Para aqueles que usam AR4 onde
scoped
foi removido, minha outra resposta fornece um scoped
semanticamente equivalente polyfil que all
não é um substituto equivalente, apesar do que a documentação do AR sugere. Responda aqui:Com Rails 4, Model.scoped está obsoleto, mas Model.all não pode substituí-lo