我希望用户能够选择多个不同的标签,以过滤公园的结果。例如,他们应该能够找到一个公园,有以下3个标签:
1.婴儿车友好
1.很多阴凉处
1.野餐桌
我使用Ransack实现了一个表单,用户可以选择多个标签,但它被视为OR查询(返回带有任何标签的公园),而不是AND查询(返回带有所有标签的公园)。
我认为问题是所有的复选框都使用相同的tags_id_in
字段。我如何使它作为AND查询工作?
表格
<%= search_form_for @q, url: :parks do |f| %>
<span class="me-5">
<% @tags.each do |tag| %>
<%= f.check_box :tags_id_in, { multiple: true, include_hidden: false, class: "btn-check", id: tag.name.titleize + "Checkbox" }, tag.id %>
<%= f.label :tags_id_in, tag.name.titleize, class: 'btn btn-outline-secondary border mb-1', for: tag.name.titleize + "Checkbox" %>
<% end %>
</span>
<span class="me-5">
<%= f.submit 'Apply filters', class: "btn btn-secondary" %>
</span>
<% end %>
来自日志:
Started GET "/en/parks?q%5Btags_id_in%5D%5B%5D=16&q%5Btags_id_in%5D%5B%5D=19&q%5Btags_id_in%5D%5B%5D=21&commit=Apply+filters" for ::1 at 2023-02-05 09:56:58 +0200
Processing by ParksController#index as HTML
Parameters: {"q"=>{"tags_id_in"=>["16", "19", "21"]}, "commit"=>"Apply filters", "locale"=>"en"}
Park Count (19.3ms) SELECT COUNT(*) FROM (SELECT DISTINCT parks.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((32.0908425 - parks.latitude) * PI() / 180 / 2), 2) + COS(32.0908425 * PI() / 180) * COS(parks.latitude * PI() / 180) * POWER(SIN((34.8154259 - parks.longitude) * PI() / 180 / 2), 2))) AS distance, MOD(CAST((ATAN2( ((parks.longitude - 34.8154259) / 57.2957795), ((parks.latitude - 32.0908425) / 57.2957795)) * 57.2957795) + 360 AS decimal), 360) AS bearing FROM "parks" LEFT OUTER JOIN "tagifications" ON "tagifications"."park_id" = "parks"."id" LEFT OUTER JOIN "tags" ON "tags"."id" = "tagifications"."tag_id" WHERE "tags"."id" IN (16, 19, 21) AND (parks.latitude BETWEEN -899289.5150762305 AND 899353.6967612305 AND parks.longitude BETWEEN -1061478.8079855754 AND 1061548.4388373755 AND (6371.0 * 2 * ASIN(SQRT(POWER(SIN((32.0908425 - parks.latitude) * PI() / 180 / 2), 2) + COS(32.0908425 * PI() / 180) * COS(parks.latitude * PI() / 180) * POWER(SIN((34.8154259 - parks.longitude) * PI() / 180 / 2), 2)))) BETWEEN 0.0 AND 100000000)) subquery_for_count
更新:我还尝试使用in_all,我认为根据文档应该可以完成我想要的任务。但是,如果选择了多个标记,我就没有结果。生成的SQL查询是...WHERE...("tags"."id" IN (21) AND "tags"."id" IN (22))...
。
看起来像这里报告的相同问题:github.com/activerecord-hackery/ransack/issues/108
1条答案
按热度按时间shstlldc1#
生成的SQL显示使用了
IN (16,19,21)
,这被视为一系列OR条件。为了实现一系列AND条件的等效性,可以考虑使用额外的group by和count,例如
你必须得到所有3个标签行才能得到3的计数。当然,这是假设你不会有任何标签重复的公园。
以下内容未经验证,但在控制器代码中使用如下逻辑: