Pertanyaan Anda mungkin dapat dipecahkan tanpa persimpangan, seperti:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Namun berikut ini adalah pendekatan umum yang saya gunakan untuk membangun persimpangan seperti kueri di 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'))
Ini akan menghasilkan SQL dalam bentuk:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Anda dapat membuat subkueri sebanyak yang diperlukan dengan pendekatan di atas berdasarkan kondisi/penggabungan apa pun, dll. selama setiap subkueri mengembalikan id orang yang cocok dalam kumpulan hasil.
Setiap set hasil subkueri akan DIAND bersama sehingga membatasi set yang cocok pada perpotongan semua subkueri.
PERBARUI
Bagi mereka yang menggunakan AR4 di mana scoped
telah dihapus, jawaban saya yang lain memberikan scoped
. yang setara secara semantik polyfil yang all
bukan pengganti yang setara untuk terlepas dari apa yang disarankan oleh dokumentasi AR. Jawab di sini:Dengan Rails 4, Model.scoped tidak digunakan lagi tetapi Model.all tidak dapat menggantikannya