【问题标题】:How to create a Rails scope that matches multiple HABTM records如何创建匹配多个 HABTM 记录的 Rails 范围
【发布时间】:2019-01-21 18:06:06
【问题描述】:

我有一个类似于 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 和 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]

【问题讨论】:

  • tags 表上加入和查询与在上述任一场景中使用stories_tags 加入表的行为相同

标签: ruby-on-rails activerecord


【解决方案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

【讨论】:

    猜你喜欢
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 2012-04-11
    相关资源
    最近更新 更多