【问题标题】:Self referential association in RailsRails 中的自引用关联
【发布时间】:2020-03-04 04:15:37
【问题描述】:

我正在尝试弄清楚如何在 Rails 中进行自引用关联。我是 Rails 初学者。

基本上,我有一个模型Group。每个组可以有许多子组。我觉得我已经尝试了所有方法,但我无法让加入工作。

我现在拥有的是

# GroupSubGroup Model
class GroupSubGroup < ApplicationRecord
  belongs_to :group
  belongs_to :sub_group, class_name: 'Group'
end

然后我的组模型看起来像

     has_many :group_sub_groups
     has_many :sub_groups, foreign_key: :sub_group_id, through: :group_sub_groups, class_name: 'GroupSubGroup'
     has_many :groups, through: :sub_groups
     has_many :groups, class_name: 'GroupSubGroup'

我的迁移看起来像

    create_table :group_sub_groups do |t|
      t.integer :group_id, index: true, foreign_key: { to_table: :groups }
      t.references :sub_group, index: true, foreign_key: { to_table: :groups }

      t.timestamps
    end

我的主要问题是我可以使用parent_group.sub_groups.new 在连接表中添加一个新的GroupSubGroup 行,但是当我检索父组并循环它的sub_groups 时,没有一个实例属于@987654328 @class,因此没有任何方法。

例如

Group.all.each do |group|
      group.sub_groups.each do |s|
        puts "#{s.name} is a sub group for #{group.name}"
      end
    end

引发undefined method 'name' 错误。

【问题讨论】:

  • 您的子组是否有name 作为列?假设您正确地进行迁移,您给出的错误消息只会提示您的子组没有name 作为列。

标签: ruby-on-rails activerecord


【解决方案1】:

它实际上比这个简单得多。对于子组,您不需要单独的模型/表。这就是自引用关联的全部意义所在。

让我们从组表开始并添加我们的自引用外键:

class CreateGroups < ActiveRecord::Migration[6.0]
  def change
    create_table :groups do |t|
      t.references :parent, index: true, foreign_key: { to_table: :groups }
      t.string :name
      t.timestamps
    end
  end
end

然后让我们创建一个到同一个表的一对多关联:

class Group < ApplicationRecord
  belongs_to :parent, 
    class_name: 'Group',
    inverse_of: :sub_groups
  has_many :sub_groups, 
    class_name: 'Group',
    foreign_key: 'parent_id',
    inverse_of: :parent
  scope :top_level, ->{ where(parent_id: nil) } 
end

然后您可以通过以下方式遍历顶级组及其子组:

# eager_load prevents an n+1 query
Group.top_level.eager_load(:sub_groups).each do |group|
  group.sub_groups.each do |s|
    puts "#{s.name} is a sub group for #{group.name}"
  end
end

【讨论】:

    【解决方案2】:

    我认为这将是您建立关联的方式

    has_many :group_sub_groups
    
    # The following should suffice for sub groups.  This should return all
    # sub_groups that the group has
    has_many :sub_groups, through: :group_sub_groups, source: :sub_group
    
    # The following should suffice for groups.  This should return all groups
    # where the group is a sub_group of.
    has_many :groups, through: :group_sub_groups, source: :group
    

    如下代码

    Group.all.each do |group|
      group.sub_groups.each do |s|
        puts "#{s.name} is a sub group for #{group.name}"
      end
    end
    

    这个错误很可能是因为s.name。在您的原始实现中,sub_groups 有一个 class_name: 'GroupSubGroup' 类,这不是您想要的。使用我上面提到的关联应该可以解决该错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多