11

tôi có 2 mô hình:Rails habtm và tìm kiếm kỷ lục với hiệp hội không

class User < ActiveRecord::Base 
    has_and_belongs_to_many :groups 
end 

class Group < ActiveRecord::Base 
    has_and_belongs_to_many :users 
end 

Tôi muốn thực hiện một phạm vi (đó là quan trọng - cho hiệu quả và cho khả năng phạm vi chuỗi) trả về người dùng đó doesn' t thuộc về ANY Nhóm. Sau nhiều lần thử, tôi đã thất bại khi thực hiện một phương thức thay vì phạm vi, làm cho collect trên User.all xấu và không đúng.

Bất kỳ trợ giúp nào?

Và có thể cho câu hỏi thứ 2: Tôi đã quản lý phạm vi trả về Người dùng thuộc bất kỳ nhóm nào đã cho (được cho là một mảng của id).

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

Nó có đẹp hơn/đẹp hơn không? (Sử dụng Rails 3.0.9)

Trả lời

17

Bảng tham gia ngầm của bạn sẽ được đặt tên là groups_users dựa trên quy ước đặt tên. Xác nhận nó một lần trong db của bạn. Giả sử nó là:

Trong phiên bản mới hơn 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") 
} 

Đối với phiên bản Rails cũ:

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.*" 
} 
+0

cảm ơn, nó đã thực hiện thủ thuật :) – schiza

+1

Bạn có cần DISTIN không CT trong trường hợp này, nơi sẽ không có mối quan hệ tham gia cho kết quả trả về, và do đó không có sự lặp lại của người sử dụng? –

+0

'DISTINCT' là không cần thiết. Tôi đã thêm cú pháp mới cần thiết cho Rails 4 trở lên (tôi nghĩ). – slhck

2

Nếu bạn chuyển đổi từ HABTM để has_many thông qua hiệp hội (linh hoạt hơn), sau đó bạn có thể sử dụng một cái gì đó như thế này:

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