Vaše otázka je pravděpodobně řešitelná bez průniku, něco jako:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Nicméně následující je obecný přístup, který používám pro vytváření křižovatek, jako jsou dotazy v 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'))
Vygeneruje SQL ve tvaru:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Výše uvedeným přístupem můžete vytvořit libovolný počet poddotazů na základě jakýchkoli podmínek/připojení atd., pokud každý poddotaz vrátí ID odpovídající osoby ve své sadě výsledků.
Každá sada výsledků poddotazu bude spojena součinem AND, čímž se sada shody omezí na průnik všech poddotazů.
AKTUALIZACE
Pro ty, kteří používají AR4, kde scoped
byla odstraněna, moje druhá odpověď poskytuje sémanticky ekvivalentní scoped
polyfil, který all
není ekvivalentní náhradou navzdory tomu, co navrhuje dokumentace AR. Odpovězte zde:S Rails 4 je Model.scoped zastaralý, ale Model.all jej nemůže nahradit