Rails, Ransack: So suchen Sie in der HABTM-Beziehung nach "allen" Übereinstimmungen anstelle von "allen"
Ich frage mich, ob jemand Erfahrung in der Verwendung von Ransack mit HABTM-Beziehungen hat. Meine App hatphotos
die haben eine habtm beziehung zuterms
(Begriffe sind wie Tags). Hier ist eine vereinfachte Erklärung dessen, was ich erlebe:
Ich habe zwei Fotos: Foto 1 und Foto 2. Sie haben die folgenden Begriffe:
Foto 1: A, B, C
Foto 2: A, B, D
Ich habe ein Durchsuchungsformular erstellt und im Suchformular Kontrollkästchen für alle Begriffe aktiviert:
- terms.each do |t|
= check_box_tag 'q[terms_id_in][]', t.id
Wenn ich benutze:q[terms_id_in][]
und ich überprüfe "A, C", meine Ergebnisse sind Foto 1 und Foto 2. Ich möchte nur Foto 1, weil ich nach A und C gefragt habe. In dieser Abfrage interessieren mich B oder D nicht, aber ich möchte sowohl A als auch C bei einem bestimmten Ergebnis anwesend sein.
Wenn ich benutzeq[terms_id_in_all][]
Meine Ergebnisse sind gleich Null, da keines der Fotos nur A und C enthält. Oder vielleicht, weil es nur einen Begriff pro Verknüpfung gibt, sodass keine Verknüpfung sowohl A als auch C entspricht. Unabhängig davon möchte ich, dass nur Foto 1 zurückgegeben wird.
Wenn ich eine Vielzahl vonq[terms_id_eq][]
Ich bekomme nie Ergebnisse, deshalb denke ich nicht, dass das in diesem Fall funktioniert.
Wie kann man bei einem Habtm-Join nach Modellen suchen, die mit den angegebenen Werten übereinstimmen, während nicht angegebene Werte ignoriert werden?
Oder, für alle Rails / SQL-Gurus, die nicht mit Ransack vertraut sind, wie sonst könnten Sie ein Suchformular erstellen, wie ich es für ein Modell mit einem Habtm-Join beschreibe?
Update: perdie antwort auf die verwandte frageIch bin jetzt soweit gekommen, eine Arel-Abfrage zu erstellen, die genau dazu passt. Irgendwie sollte es Ihnen möglich sein, Arel-Knoten als Ransacker oder als Cdesrosier zu verwenden, die als benutzerdefinierte Prädikate bezeichnet werden, aber bisher habe ich das nicht zum Laufen gebracht.
Aufgrund dieser Antwort richte ich den folgenden Ransack-Initialisierer ein:
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
... und richten Sie dann die folgende Methode auf Foto ein:
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
Leider scheint dies nicht zu funktionieren. Währendterms_subquery
erzeugt das korrekte SQL, das Ergebnis vonPhoto.search(:has_terms => [2,5]).result.to_sql
ist nur"SELECT \"photos\".* FROM \"photos\" "