代码之家  ›  专栏  ›  技术社区  ›  Erik J

如何创建与多个habtm记录匹配的rails作用域

  •  1
  • Erik J  · 技术社区  · 6 年前

    我有一个像CMS一样的Rails 5应用程序, Story Tag 模型。一个故事 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和3的单个连接记录,但没有返回任何内容。

      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 回复  |  直到 6 年前
        1
  •  1
  •   MrYoshiji    6 年前

    必须使用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

    推荐文章