1

我需要将用户组存储在其他组中,有点像 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

最简单的方法是什么?

4

2 回答 2

2

您可以通过在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 %>
于 2019-02-06T02:37:05.853 回答
0

我将我的 attemtp 与 Jake 的解决方案放在一个单独的答案中,以使其与原始解决方案分开,并单独对此解决方案进行评论和编辑。我不打算接受这个作为答案!此外,我将整个脚本放在这里,以便人们可以立即进行测试。该解决方案仅使用 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>]>
于 2019-02-07T20:13:25.307 回答