我想知道是否有人有使用 Ransack 与 HABTM 关系的经验。我的应用程序photos
与之有 habtm 关系terms
(术语就像标签)。这是对我所经历的事情的简化解释:
我有两张照片:照片 1 和照片 2。它们具有以下术语:
照片1:A、B、C
照片 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][]
我的结果为零,因为两张照片都只包含 A 和 C。或者,也许因为每次连接只有一个术语,所以没有连接匹配 A 和 C。无论如何,我只想返回照片 1。
如果我使用任何品种,q[terms_id_eq][]
我永远不会得到任何结果,所以我认为这在这种情况下不起作用。
那么,给定一个 habtm 连接,您如何搜索与给定值匹配的模型,同时忽略未给定的值?
或者,对于任何不熟悉 Ransack 的 rails/sql 专家,您还可以如何创建一个搜索表单,就像我为具有 habtm 连接的模型所描述的那样?
更新:根据相关问题的答案,我现在已经构建了一个正确匹配的 Arel 查询。不知何故,您应该能够将 Arel 节点用作洗劫者,或者正如 cdesrosiers 指出的那样,用作自定义谓词,但到目前为止,我还没有做到这一点。
根据该答案,我设置了以下 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\" "