Rails ActiveRecord与has_many关联相交查询

我有以下型号:

class Piece < ActiveRecord::Base has_many :instrument_pieces has_many :instruments, through: :instrument_pieces end class Instrument < ActiveRecord::Base has_many :pieces, through: :instrument_pieces has_many :instrument_pieces end class InstrumentPiece < ActiveRecord::Base belongs_to :instrument belongs_to :piece end 

我有以下查询:

 Piece .joins(:instrument_pieces) .where(instrument_pieces: { instrument_id: search_params[:instruments] } ) .find_each(batch_size: 20) do |p| 

search_params[:instruments]是一个数组。 此查询的问题在于它将检索具有任何乐器的所有乐曲,因此如果search_params[:instruments] = ["1","3"] ,则查询将返回乐器关联为1或者1的乐曲。 3或两者兼而有之。 我希望查询只返回其乐器关联包括乐器1和3的乐曲。我已经阅读了文档,但我仍然不确定如何做到这一点……

看起来我想要的是两个查询之间的交集,所以我最终做的是:

 queries = [] query = Piece.joins(:instruments) search_params[:instruments].each do |instrument| queries << query.where(instruments: {id: instrument}) end sql_str = "" queries.each_with_index do |query, i| sql_str += "#{query.to_sql}" sql_str += " INTERSECT " if i != queries.length - 1 end Piece.find_by_sql(sql_str).each do |p| 

非常难看,但ActiveRecord还不支持INTERSECT。 我想,等待ActiveRecord 5的时候了。

您可以使用where子句链接来实现此目的。 尝试:

 query = Piece.joins(:instrument_pieces) search_params[:instruments].each do |instrument| query = query.where(instrument_pieces: { instrument_id: instrument } ) end query.find_each(batch_size: 20) do |p| 

或其他版本

 query = Piece.joins(:instruments) search_params[:instruments].each do |instrument| query = query.where(instrument_id: instrument) end query.find_each(batch_size: 20) do |p|