一尘不染

Rails,Ransack:如何在HABTM关系中搜索“匹配”而不是“ ny”。

sql

我想知道是否有人有使用Ransack与HABTM关系的经验。我的应用具有photos与之的habtm关系terms(术语类似于标签)。这是我正在经历的简化解释:

我有两张照片:照片1和照片2。它们具有以下术语:

照片1:A,B,C

照片2:A,B,D

我建立了一个sacksack表单,并在搜索表单中为所有术语创建了复选框,如下所示:

- 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][]结果为nil,则因为两张照片都没有只包含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\" "


阅读 209

收藏
2021-03-10

共1个答案

一尘不染

在我对您的相关问题的回答中定义了一个自定义ransack谓词,这应该可以对您的标记进行简单的更改:

- terms.each do |t|
  = check_box_tag 'q[id_has_terms][]', t.id

更新

这样:formatter做并没有达到我的想法,并且由于Ransack存储库如何不提及“子查询”,毕竟您可能无法将其用于您想做的事情。所有可用的选项似乎都已用尽,因此只剩下猴子补丁了。

为什么不像过去通常使用活动记录(甚至使用现在的Arel查询)那样跳过ransack并查询“照片”表?您已经知道查询有效。您希望从使用Ransack获益吗?

2021-03-10