2015-11-06 3 views
1

У меня есть следующие модели: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, либо 3, либо их обоих. Я бы хотел, чтобы запрос возвращал только те части, чьи ассоциации инструментов включали оба инструмента 1 и 3. Я читал документы, но я все еще не уверен, как это можно сделать ...

ответ

0

Вы можете использовать где clause chaining для достижения этого. Попробуйте:

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| 
+0

При использовании с несколькими значениями в search_params [: instruments] этот запрос ничего не возвращает ... – 23049581029

+0

У вас на самом деле есть части, соответствующие обеим инструментам? Вы можете проверить полученный SQL-код в Rails. –

+0

Yup. Я подозреваю, что проблема может заключаться в том, что объект 'instrument_pieces' имеет только два поля:: instrument_id' и': piece_id' и эти запросы для объекта 'instrument_pieces' с': instrument_id' обоих значений. Можно ли в этом случае выполнить пересечение запросов? – 23049581029

2

Похоже, что я хотел пересечение между двумя запросами, так что я в конечном итоге делает был:

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.

+0

О, я не предполагал, что вы имеете в виду настоящий «ИНТЕРЕС», я думал, что вы просто хотите «И» условия. Теперь 'INTERSECT' определенно не поддерживается рельсами. Код, вероятно, будет выглядеть лучше, если вы просто сгенерируете строку SQL без использования ActiveRecord. –

+0

После 1 года с вашего поста, я встретил ту же проблему здесь, мне потребовалось 1 день, пока я не нашел ваш пост. http://stackoverflow.com/questions/42689938/filter-by-many-to-many-relationships/42691195#42691195 – user3448806

Смежные вопросы