Rails habtm并找到没有关联的记录

时间:2011-08-11 20:11:27

标签: ruby-on-rails activerecord associations has-and-belongs-to-many

我有2个型号:

class User < ActiveRecord::Base
    has_and_belongs_to_many :groups
end

class Group < ActiveRecord::Base
    has_and_belongs_to_many :users
end

我想制作一个范围(这对于效率和链接范围的能力很重要),它会返回不属于 ANY 组的用户。 经过多次尝试,我没有做一个方法而不是范围,这使collect上的User.all变得丑陋而且......不对。

任何帮助?

也许是第二个问题: 我设法创建一个范围,返回属于任何给定组的用户(以id的数组形式给出)。

scope :in_groups, lambda { |g|
        {
          :joins      => :groups,
          :conditions => {:groups => {:id => g}},
          :select     => "DISTINCT `users`.*" # kill duplicates
        }
      }

可以更好/更漂亮吗? (使用Rails 3.0.9)

3 个答案:

答案 0 :(得分:17)

根据命名约定,您的隐式连接表将被命名为groups_users。在数据库中确认一次。假设它是:

在较新的Rails版本中:

scope :not_in_any_group -> {
    joins("LEFT JOIN groups_users ON users.id = groups_users.user_id")
    .where("groups_users.user_id IS NULL")
}

对于较旧的Rails版本:

scope :not_in_any_group, {
    :joins      => "LEFT JOIN groups_users ON users.id = groups_users.user_id",
    :conditions => "groups_users.user_id IS NULL",
    :select     => "DISTINCT users.*"
}

答案 1 :(得分:3)

如果您从HABTM转换为has_many到(更灵活)关联,那么您可以使用以下内容:

class Group < ActiveRecord::Base
  has_many :groups_users, dependent: :destroy
  has_many :users, through: :groups_users, uniq: true

  scope :in_groups, -> { includes(:groups_users).where(groups_users: {group_id: nil}) }
end

class User < ActiveRecord::Base
  has_many :groups_users, dependent: :destroy
  has_many :groups, through: :groups_users
end

class GroupsUser < ActiveRecord::Base
  belongs_to :group
  belongs_to :user
end

答案 2 :(得分:0)

在 Rails >= 5 中,有 left_outer_joins,结合 new(ish) .where() 语法,使范围更具可读性:

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups

  scope :not_in_any_group, -> {
    left_outer_joins(:groups)
    .where(groups_users: { user_id: nil })
  }
end

class Group < ActiveRecord::Base
  has_and_belongs_to_many :users
end