如何检查加入条件?

时间:2015-10-11 12:31:21

标签: ruby-on-rails ruby

我正在尝试在我的Widget搜索中为用户设置过滤。我希望他们能够点击多个标签,并仅返回应用了正确标签的结果。

表格设置如下:

  • Widget有很多标签,通过标签
  • 标签有许多小部件,通过标记
  • Taggings是一个连接表

在我的控制器中,我正在迭代小部件,并检查标签上的条件加入:

@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]

我是否在检查标签和小部件之间的连接方面做错了什么?

4 个答案:

答案 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条件来解决此问题。