首页 > 解决方案 > 使用连接表过滤用户

问题描述

我有用于用户、标签和连接表标签的表。

我目前正在使用scope通过不同的变量过滤用户,例如:

scope = scope.where('users.created_at > :created_after', created_after: params[:created_after])

我正在尝试通过分配给他们的标签(通过has many关系)过滤用户。

在用户模型中:

has_many :taggings, as: :taggable
has_many :tags, through: :taggings

用户表:

╔════╦══════════════╦
║ id ║  name        ║
╠════╬══════════════╬
║  1 ║ Picard       ║ 
║  2 ║ Kirk         ║
║  3 ║ Sisko        ║
║  4 ║ Janeway      ║
╚════╩══════════════╩

标签表:

╔════╦══════════════╦
║ id ║  Tag         ║ 
╠════╬══════════════╬
║  1 ║ TOS          ║  
║  2 ║ TNG          ║ 
║  3 ║ DS9          ║ 
║  4 ║ VOY          ║ 
╚════╩══════════════╩

标记表:

╔════╦═══════════╦═══════════════╦═══════════════════════╦
║ id ║  tag_id   ║ taggable_id   ║ taggable_type         ║ 
╠════╬═══════════╬═══════════════╬═══════════════════════╣
║  1 ║ 1         ║    1          ║  User                 ║
║  2 ║ 1         ║    4          ║  Organization         ║
║  3 ║ 2         ║    2          ║  User                 ║
║  4 ║ 1         ║    3          ║  User                 ║
╚════╩═══════════╩═══════════════╩═══════════════════════╝

我试过类似的东西:

SELECT * FROM users u
  JOIN taggings j, tags t
  WHERE t.tag = <tag>
    AND t.id = j.tag_id
    AND j.taggable_type = 'User'
    AND u.id = j.taggable_id

标签: sqlruby-on-railspostgresql

解决方案


您可以获得计数并使用必须规定用户必须具有一个或多个标签:

tags = ["TOS", "TNG"]
User.joins(:tags)
    .where(tags: { tag: tags })
    .group(:id)
    .having(
      # Arel for "COUNT(tags.*) >= ?"
      Tag.arel_table[Arel.star].count.gte(tags.length)
    )

由于您使用的是多态关联,因此您可能希望将其烘焙到一个模块中,以便您可以重用它:

module Taggable
  extend ActiveSupport::Concern
  included do
    has_many :taggings, as: :taggable
    has_many :tags, through: :taggings
  end

  class_methods do
    def with_tags(*tags) 
      joins(:tags)
        .where(tags: { tag: tags })
        .group(:id)
        .having(  
          Tag.arel_table[Arel.star]
             .count.gteq(tags.length)
        )
    end
  end
end
class User < ApplicationRecord
  include Taggable
end

推荐阅读