Câu hỏi của bạn có thể giải được mà không cần giao nhau, đại loại như:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Tuy nhiên, sau đây là cách tiếp cận chung mà tôi sử dụng để xây dựng giao lộ như các truy vấn trong 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'))
Nó sẽ tạo ra SQL có dạng:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Bạn có thể tạo bao nhiêu truy vấn con theo yêu cầu với phương pháp trên dựa trên bất kỳ điều kiện / phép nối nào, v.v. miễn là mỗi truy vấn con trả về id của một người phù hợp trong tập kết quả của nó.
Mỗi tập hợp kết quả truy vấn con sẽ được AND kết hợp với nhau, do đó hạn chế tập hợp phù hợp ở giao điểm của tất cả các truy vấn con.
CẬP NHẬT
Đối với những người sử dụng AR4 trong đó scoped
đã bị xóa, câu trả lời khác của tôi cung cấp scoped
tương đương về mặt ngữ nghĩa polyfil mà all
không phải là sự thay thế tương đương cho bất chấp những gì tài liệu AR gợi ý. Trả lời ở đây: Với Rails 4, Model.scoped không được dùng nữa nhưng Model.all không thể thay thế nó