Rails, Ransack: Jak wyszukiwać relacje HABTM dla „wszystkich” meczów zamiast „dowolnych”
Zastanawiam się, czy ktoś ma doświadczenie w używaniu Ransack z relacjami HABTM. Moja aplikacja maphotos
które mają relację habtmterms
(terminy są jak znaczniki). Oto uproszczone wyjaśnienie tego, czego doświadczam:
Mam dwa zdjęcia: zdjęcie 1 i zdjęcie 2. Mają następujące terminy:
Zdjęcie 1: A, B, C
Zdjęcie 2: A, B, D
Zbudowałem formularz okupu i zaznaczam pola wyboru w formularzu wyszukiwania dla wszystkich terminów, takich jak:
- terms.each do |t|
= check_box_tag 'q[terms_id_in][]', t.id
Jeśli używam:q[terms_id_in][]
i sprawdzam „A, C” moje wyniki to zdjęcie 1 i zdjęcie 2. Chcę tylko zdjęcie 1, ponieważ poprosiłem o A i C, w tym zapytaniu nie obchodzi mnie B ani D, ale chcę zarówno A, jak i C być obecnym na danym wyniku.
Jeśli używamq[terms_id_in_all][]
moje wyniki są zerowe, ponieważ żadne zdjęcie nie zawiera tylko A i C. Lub może dlatego, że na jedno połączenie przypada tylko jeden termin, więc żadne połączenie nie pasuje zarówno do A, jak i C. Niezależnie od tego chcę zwrócić tylko zdjęcie 1.
Jeśli używam jakiejkolwiek odmianyq[terms_id_eq][]
Nigdy nie otrzymuję żadnych wyników, więc nie sądzę, żeby to działało w tym przypadku.
Tak więc, biorąc pod uwagę połączenie habtm, jak szukać modeli, które pasują do podanych wartości, ignorując nie podane wartości?
Albo, w przypadku jakichkolwiek guru / szyn nie znających Ransacka, jak inaczej mógłbyś stworzyć formularz wyszukiwania, jak opisuję model z połączeniem habtm?
Aktualizacja: zaodpowiedź na powiązane pytanie, Teraz doszedłem do skonstruowania zapytania Arel, które poprawnie pasuje do tego. W jakiś sposób powinieneś być w stanie używać węzłów Arel jako ransackerów, lub jak wskazywali cdesrosiers, jako predykaty niestandardowe, ale jak dotąd nie działałem.
Zgodnie z tą odpowiedzią ustawiam następujący inicjator okupu:
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
... a następnie skonfiguruj następującą metodę na zdjęciu:
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
Niestety to nie działa. Podczasterms_subquery
tworzy poprawny SQL, wynikPhoto.search(:has_terms => [2,5]).result.to_sql
jest tylko"SELECT \"photos\".* FROM \"photos\" "