如何创建与多个HABTM记录匹配的Rails范围

时间:2019-01-21 18:06:07

标签: ruby-on-rails activerecord

我有一个类似CMS的Rails 5应用,具有StoryTag模型。故事has_and_belongs_to_many :tags。我想创建一个范围,在其中可以传递多个标签,并获得包含传递给我的所有标签的所有故事。

例如:

story_1.tags   # => [tag_a, tag_c]
story_2.tags   # => [tag_b, tag_c]
story_3.tags   # => [tag_a, tag_b, tag_c]

# Desired behavior
Story.with_tags([tag_a, tag_c])  # => [story_1, story_3]
Story.with_tags([tag_b, tag_c])  # => [story_2, story_3]
Story.with_tags([tag_a, tag_b])  # => [story_3]

我尝试制作单个with_tag范围并将多个链接链接在一起,但是似乎进行了一个查询,尝试查找标记ID为1 AND 3(不返回任何内容)的单个联接记录。 / p>

  def self.with_tag(tag)
    joins(:tags).where(tags: { id: tag })
  end

Story.with_tag(tag_a).with_tag(tag_c)  # => []

我也尝试过将所有标签ID传递到联接表上的单个where子句中,但是随后我得到了具有任何标签的所有故事(更多的OR查询,我正在寻找AND)

  def self.with_tags(tags)
    joins(:stories_tags).where(stories_tags: { tag_id: tags }).distinct
  end

Story.with_tags([tag_a, tag_c])  # => [story_1, story_2, story_3]

1 个答案:

答案 0 :(得分:1)

您必须使用SQL HAVING子句:

ids = [1,2,3]
Story.joins(:tags)
  .where(:tags => { id: ids })
  .group('stories.id')
  .having('count(tags.id) >= ?', ids.size)
#                         ^^ if you want to get stories having exactly the tags 
#                            provided, use equal instead

相似的问题:Rails filtering records in many to many relationship