Rails, Ransack: Как искать отношения HABTM для «всех» совпадений вместо «любых»
Мне интересно, есть ли у кого-нибудь опыт использования Ransack с HABTM-связями. Мое приложение имеетphotos
которые имеют отношения habtm сterms
(термины похожи на теги). Вот упрощенное объяснение того, что я испытываю:
У меня есть две фотографии: Фото 1 и Фото 2. Они имеют следующие условия:
Фото 1: А, Б, В
Фото 2: A, B, D
Я построил форму для разграбления, и я делаю флажки в форме поиска для всех терминов, например так:
- terms.each do |t|
= check_box_tag 'q[terms_id_in][]', t.id
Если я использую:q[terms_id_in][]
и я проверяю «A, C», мои результаты - Фото 1 и Фото 2. Я хочу только Фото 1, потому что я попросил A и C, в этом запросе мне нет дела до B или D, но я хочу и A, и C присутствовать на данном результате.
Если я используюq[terms_id_in_all][]
мои результаты равны нулю, потому что ни одна фотография не включает в себя только А и С. Или, возможно, потому, что в соединении есть только один термин, поэтому объединение не соответствует ни А, ни С. Независимо от того, я хочу, чтобы была возвращена только фотография 1.
Если я использую любое разнообразиеq[terms_id_eq][]
Я никогда не получаю никаких результатов, поэтому я не думаю, что это работает в этом случае.
Итак, учитывая соединение habtm, как вы будете искать модели, которые соответствуют заданным значениям, игнорируя при этом не заданные значения?
Или, для любых rails / sql гуру, не знакомых с Ransack, как еще вы могли бы создать форму поиска, как я описываю для модели с habtm соединением?
Обновление: заответ на связанный вопросТеперь я дошел до построения запроса Arel, который правильно соответствует этому. Каким-то образом вы должны иметь возможность использовать узлы Arel в качестве вымогателей или, как указали кадры, в качестве пользовательских предикатов, но до сих пор я не получил эту работу.
Для этого ответа я установил следующий инициализатор Ransack:
Ransack.configure do |config|
config.add_predicate 'has_terms',
:arel_predicate => 'in',
:formatter => proc {|term_ids| Photo.terms_subquery(term_ids)},
:validator => proc {|v| v.present?},
:compounds => true
end
... и затем настройте следующий метод на Фото:
def self.terms_subquery(term_ids)
photos = Arel::Table.new(:photos)
terms = Arel::Table.new(:terms)
photos_terms = Arel::Table.new(:photos_terms)
photos[:id].in(
photos.project(photos[:id])
.join(photos_terms).on(photos[:id].eq(photos_terms[:photo_id]))
.join(terms).on(photos_terms[:term_id].eq(terms[:id]))
.where(terms[:id].in(term_ids))
.group(photos.columns)
.having(terms[:id].count.eq(term_ids.length))
).to_sql
end
К сожалению, это не похоже на работу. Покаterms_subquery
выдает правильный SQL, результатPhoto.search(:has_terms => [2,5]).result.to_sql
просто"SELECT \"photos\".* FROM \"photos\" "