通过递归 has_many 关系创建 has_many 关系

时间:2021-07-08 15:32:41

标签: ruby-on-rails ruby activerecord ruby-on-rails-6

情况:

class Company < ActiveRecord::Base
  has_many :groups #<-- recursive sub-groups
  has_many :profiles, through: :groups #<-- This only returns the :profiles of the first groups layer
end

class Group < ActiveRecord::Base
  belongs_to :company, optional: true
  belongs_to :group, optional: true
  validate :company_xor_group
  has_many :groups
  has_many :profiles
end

class Profile < ActiveRecord::Base
  belongs_to :group
end

示例数据:

  company = Company.new
  group = Group.new.profiles.build(name: 'A')
  sub_group = Group.new.profiles.build([{name: 'B'},{name: 'C'}])
  group.groups << sub_group
  company.groups << group

因此,一家公司有一个组,其中包含一个配置文件和一个子组,其中包含 2 个配置文件。

所以我想获得公司的所有资料。目前,has_many :profiles, through: :groups 关系仅返回第一个子组的配置文件:

  company.profiles.length # 1

我正在寻找返回 ActiveRecord AssociationProxy 的解决方案。我尝试了以下方法:

# Company Model
def all_profiles
  groups.map(&:all_profiles)
end

# Group Model
def all_profiles
  profiles + groups.map(&:all_profiles)
end

但这会返回一个数组,而不是一个 AssociationProxy

1 个答案:

答案 0 :(得分:0)

正如@spickermann 回应的那样,对递归表的巨大帮助是 Awesome Nested Set

我的问题“如何让它返回 ActiveRecord AssociationProxy?”的答案是@arieljuod:

# Company Model
def all_profiles
  Profile.where(group_id: groups.map(&:all_groups).flatten.map(&:id))
end

# Group Model
def all_groups
  [self].push(groups.map(&:all_groups)).flatten.compact
end

在我的解决方案中,这仍然非常有效,因为递归组是预加载的。因此,all_groups 方法不会触发任何新查询。

相关问题