Въпросът ви вероятно е разрешим без пресичане, нещо като:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Следното обаче е общ подход, който използвам за конструиране на заявки като пресечни точки в 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'))
Той ще генерира SQL във формата:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Можете да създадете толкова подзаявки, колкото е необходимо с горния подход, базиран на всякакви условия/съединявания и т.н., стига всяка подзаявка да връща идентификатора на съвпадащ човек в своя набор от резултати.
Всеки набор от резултати от подзаявка ще бъде Интегриран заедно, като по този начин се ограничава наборът за съвпадение до пресечната точка на всички подзаявки.
АКТУАЛИЗИРАНЕ
За тези, които използват AR4, където scoped
беше премахнат, другият ми отговор предоставя семантично еквивалентен scoped
polyfil който all
не е еквивалентен заместител на въпреки това, което предлага AR документацията. Отговорете тук:С Rails 4, Model.scoped е остарял, но Model.all не може да го замени