簡體   English   中英

ActiveRecord具有嵌套組的has_and_belongs_to_many

[英]Activerecord has_and_belongs_to_many with nested groups

我需要將用戶組存儲在其他組中,例如Windows Active Directory。

我有以下工作原理

ActiveRecord::Schema.define do
  create_table :users do |table|
    table.column :name, :string
  end
  create_table :groups do |table|
    table.column :name, :string
  end
  create_join_table :users, :groups do |t|
  end
end

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups
end

class Group < ActiveRecord::Base
  has_and_belongs_to_many :users
  # has_and_belongs_to_many :groups
end

peter  = User.create(id: 1, Name: 'Peter')
thomas = User.create(id: 2, Name: 'Thomas')
inf = Group.create(id: 1, Name: 'Informatics')

peter.groups << inf
inf.users << thomas
p User.find_by(Name: 'Peter').groups
p Group.find_by(Name: 'Informatics').users

但我也想做以下事情

sm = Group.create(id: 2, Name: 'System')
inf.groups << sm

這樣做的最簡單方法是什么?

您可以通過在Group模型中使用自引用關系來完成此操作。 這是表中的記錄可能指向同一表中其他記錄的地方。

基本上,主要組的parent_id將為NULL ,子組的parent_id設置為其父組的列ID。

組型號:

has_many :users

has_many :sub_groups, class_name: "Group", foreign_key: :parent_id
has_many :sub_group_users, through: :sub_groups, source: :users 
belongs_to :parent, class_name: 'Group', foreign_key: :parent_id, optional: true
# This is a scope to load the top level groups and eager-load their users, sub-groups, and the sub-groups' users too.
scope :top_level, -> { where(parent_id: nil).includes :users, sub_groups: :users}

組控制器:

def show
  @group            = Group.find(params[:id])
  @category         = @group.parent
  @users            = @group.users
  @sub_group        = @group.sub_groups.first
  unless @sub_group.nil?
    @relatives      = @group.sub_group_users
  end
end

private

  def cat_params
    params.require(:group).permit(:name, :parent_id, :sub_group)
  end


  def main_group
    @group = Group.parent_id.nil?
  end

在您的groups表中,添加以下列: t.integer "parent_id"

users表中,添加以下列: t.integer "group_id"

您還需要將:group_id添加到user_params中(在用戶控制器中)。

用戶模型: belongs_to :group

在您的組顯示視圖中:

<% if @category %>
  <% @users.each do |user| %>

  <% end %>
<% else %>
  <% @relatives&.each do |user| %>

  <% end %>
<% end %>

我將帶有Jake解決方案的attemtp放在一個單獨的答案中,以使其與原始版本區分開來,並使僅對該解決方案進行評論和編輯成為可能。 我無意接受此作為答案! 另外,我將整個腳本放在這里,以便人們可以立即進行測試。 該解決方案僅使用2個表,而不是原來的3個表,這很好,但是還不完整,請參閱代碼末尾的說明。

require 'active_record'
require 'logger'

ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database  => ":memory:"
)

ActiveRecord::Schema.define do
  create_table :users do |table|
    table.column :name, :string
    table.column :group_id, :integer
  end
  create_table :groups do |table|
    table.column :name, :string
    table.column :user_id, :integer
    table.column :parent_id, :integer
  end
end

class User < ActiveRecord::Base
  belongs_to :group
  has_many :groups
end

class Group < ActiveRecord::Base
  has_many :users
  has_many :sub_groups, class_name: "Group", foreign_key: :parent_id
  has_many :sub_group_users, through: :sub_groups, source: :users 
  belongs_to :parent, class_name: 'Group', foreign_key: :parent_id, optional: true
  # This is a scope to load the top level groups and eager-load their users, sub-groups, and the sub-groups' users too.
  scope :top_level, -> { where(parent_id: nil).includes :users, sub_groups: :users}
end

peter  = User.create(id: 1, name: 'Peter')
thomas = User.create(id: 2, name: 'Thomas')
erika  = User.create(id: 3, name: 'Erika')
inf    = Group.create(id: 1, name: 'Informatics')
devs   = Group.create(id: 2, name: 'Devs')
log    = Group.create(id: 3, name: 'Logistics')

# peter.groups << inf # doesn't work
devs.users << thomas
devs.users << peter
inf.users << erika

# expect inf.groups << devs to work
inf.sub_groups << devs

# doesn't work
p peter.groups #<ActiveRecord::Associations::CollectionProxy []>

# only gives users added straight to the group
p inf.users #<ActiveRecord::Associations::CollectionProxy [#<User id: 3, name: "Erika", group_id: 1>]>

# this should be added to inf.users
p inf.sub_group_users 
#<ActiveRecord::Associations::CollectionProxy [#<User id: 1, name: "Peter", group_id: 2>, #<User id: 2, name: "Thomas", group_id: 2>]>

# works
p Group.top_level
#<ActiveRecord::Relation [#<Group id: 1, name: "Informatics", user_id: nil, parent_id: nil>]>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM