我正在尝试在我的Widget搜索中为用户设置过滤。我希望他们能够点击多个标签,并仅返回应用了正确标签的结果。
表格设置如下:
在我的控制器中,我正在迭代小部件,并检查标签上的条件加入:
@widgets = Widget.all
@current_tags = [1,5,7,10,15] # Passed in from params
@current_tags.each do |t|
@widgets = @widgets.joins(:tags).where("tags.id=?", t)
end
我只想要返回那些所有这些标记的小部件。
这似乎适用于一个标记,但是一旦您单击另一个标记,一旦您选择多个标记就会产生问题。例如,这会按预期返回小部件1:
# Widget 1 is joined to tags 1,5,7,9
@current_tags = [5]
这不会返回任何结果,即使它应该返回小部件1:
# Widget 1 has tags 1,5,7,9
@current_tags = [5,7]
我是否在检查标签和小部件之间的连接方面做错了什么?
答案 0 :(得分:1)
你可能会对act-as-taggable-on gem感兴趣,但对于你的问题,这是一个艰难的问题!肯定有一个强大的Rails成语你可以使用,但这是一个强力方法:
unless @current_tags.empty?
# set initial state to widgets that match the first tag
@widgets = @widgets.joins(:tags).where("tags.id=?", @current_tags.shift)
@current_tags.each do |t|
# then keep only widgets in initial state AND the next tag
@widgets &= @widgets.joins(:tags).where("tags.id=?", t)
end
end
答案 1 :(得分:1)
您宁愿将查询更改为:
file.txt
它正在按用户选择的标签查找小部件。
答案 2 :(得分:0)
如果每个小部件仅与标签链接一次,您可以执行以下操作:
@widgets =
Widget
.select('widgets.id')
.joins("INNER JOIN taggings ON taggings.widget_id = widgets.id")
.where(tag_id: @current_tags)
.group("widgets.id")
.having("COUNT(*) = #{@current_tags.length}")
编写此代码的另一种方法:
widget_ids =
Tagging
.select(:widget_id)
.where(tag_id: @current_tags)
.group(:widget_id)
.having("COUNT(*) = #{@current_tags.length}")
@widgets = Widget.where(id: widget_ids)
答案 3 :(得分:0)
有点尴尬的方法是让你的循环链EXISTS
像这样:
@widgets = Widget.all
@current_tags = [1,5,7,10,15]
@current_tags.each do |t|
@widgets = @widgets.where(
widget.taggings.where(tag_id: t).exists # << a bit of Arel for ya
)
end
理论上应该 。在实践中,我已经看到像这个错误的参数绑定错误的代码,我。即Rails为两个占位符传递一个参数。您可能可以通过使用.where('taggings.tag_id = ?', t)
之类的纯SQL条件来解决此问题。