3

本质上,我希望具有以下结构:

class Group < ActiveRecord::Base

end

class Person < ActiveRecord::Base

end

Group_1 (parent)
  Group_2 (child)
    Person_1 (grandchild)
    Person_2 (grandchild)
  Person_3 (child)
  Group_3 (child)
    Person_4 (grandchild)
    Group_4 (grandchild)
      Person_5 (great grandchild)

我通过尝试以下 gem 进行了研究:acts_as_tree、ancestry、nested_sets 和closure_tree。

他们能够保持一棵树,这是我面临的挑战的一半;但是他们无法将另一个模型添加到树结构中,因为他们总是期望孩子们是同一个模型。[例如:ActiveRecord::AssociationTypeMismatch: Group (#2179078840) 预期,从closure_tree gem 中得到 Person(#2171128160)]

无论如何,是否有可能让上面定义的结构与树内的两个不同模型一起工作?

4

6 回答 6

0

本质上,您希望 Person 从 Group 继承。我不知道为什么你会想要这种结构,因为组和人不是同一类型的东西。

也许您想详细说明您尝试共享的功能。在两个非常不同的对象之间共享功能的更“红宝石”方式是通过模块,而不是通过继承。

于 2012-10-17T18:57:56.150 回答
0

我会使用该habtm方法来解决这个问题。但是您可能需要注意如何构建数据库表。Rails 代码看起来是这样的

class Group < ActiveRecord::Base
  has_and_belongs_to_many :people, class: Person
end

class Person < ActiveRecord::Base
  has_and_belongs_to_many :groups
end
于 2012-10-17T21:18:17.277 回答
0

您是否需要 Tree 附带的功能。如果没有,你可以做一些简单的事情......

在每个对象上放置一个 group_id。一个 nil group_id 意味着它属于根。

class Group < ActiveRecord::Base
  belongs_to :group  # The parent

  has_many :groups
  has_many :people
end

class Person < ActiveRecord::Base
  belongs_to :group

end
于 2012-10-17T23:51:09.113 回答
0

您可以定义将用于“树节点”的模型。每个节点可以有一个布尔字段来指示它是否是叶子,另一个字段(或多个字段)指向该节点“持有”的组/个人。(如果您只使用一个字段来指向 Group/Person,那么您可以使用多态关联,或者您可以编写一个自定义 SQL 查询,根据 "groups" 或 "people" 的值进行检索叶”字段。)

于 2012-10-17T18:53:53.527 回答
0

closure_tree 测试中有一些使用 STI 或单表继承的示例,这就是您想要使用的样子。不过,请阅读 STI——“组”似乎与“组”具有相同类型的字段或行为,因此这可能不是正确的解决方案。

但是,假设它是创建一个数据库迁移,它将一个字符串类型的列添加到您的模型中。我会将该表命名为通用名称,例如“节点”。

class AddTypeToNode < ActiveRecord::Migration
  def change
    add_column :nodes, :type, :string
  end
end

然后创建一个基类和你的子类:

class Node < ActiveRecord::Base
  abstract_class = true
  acts_as_tree
end

class Group < Node
end

class Person < Node
end

然后你就可以这样做了:

g1 = Group.create(:name => "Group_1")
g2 = g1.add_child(Group.create(:name => "Group_2"))
p1 = g2.add_child(Person.create(:name => "Person_1"))
p2 = g2.add_child(Person.create(:name => "Person_2"))
…
于 2013-02-26T05:27:02.057 回答
0

完全工作 这可以改进,但我只做了你想要的


gem 'ancestry'

组.rb


class Group < ActiveRecord::Base
  attr_accessible :parent_id, :name
  has_many :people
  attr_accessor :relationship
  has_ancestry

  def people_group_children
    (people + children).sort_by(&:created_at)
  end

  RELATIONSHIP = ['parent', 'child', 'grandchild']
  def relationship_by_depth(depth_diff)
    @relationship = RELATIONSHIP[depth_diff] || (depth_diff-2) * 'great ' + RELATIONSHIP[2]
  end

  def arrange_as_desired(ancestor_depth = 0, parent_depth = 0)
    output = '<ul>'.html_safe
    output.safe_concat name + '(' + relationship_by_depth(depth - ancestor_depth) + ')'
    people_group_children.map do |child|
      output.safe_concat '<li>'
      output.safe_concat child.arrange_as_desired(ancestor_depth, depth)
      output.safe_concat '</li>'
    end
    output.safe_concat '</ul>'
    output
  end
end

人.rb


class Person < ActiveRecord::Base
  attr_accessible :group_id, :name
  belongs_to :group
  attr_accessor :relationship, :depth
  def parent; group; end

  def people_group_children; []; end

  RELATIONSHIP = ['parent', 'child', 'grandchild']
  def relationship_by_depth(depth_diff)
    @relationship = RELATIONSHIP[depth_diff] || 'great ' * (depth_diff-2) + RELATIONSHIP[2]
  end

  def arrange_as_desired(ancestor_depth = 0, parent_depth = 0)
    output = '<ul>'.html_safe
    @depth = parent_depth + 1
    output.safe_concat name + "(#{relationship_by_depth(depth - ancestor_depth)})"
    people_group_children.map do |child|
      output.safe_concat '<li>'
      output.safe_concat child.arrange_as_desired(ancestor_depth, depth)
      output.safe_concat '</li>'
    end
    output.safe_concat '</ul>'
    output
  end
end

组\show.html.erb


<ul>
  <%= raw @group.arrange_as_desired %>
</ul>


迁移

create_groups.rb


class CreateGroups < ActiveRecord::Migration
  def change
    create_table :groups do |t|
      t.string :name
      t.string :ancestry

      t.timestamps
    end
  end
end

create_people.rb


class CreatePeople < ActiveRecord::Migration
  def change
    create_table :people do |t|
      t.integer :group_id
      t.string :name

      t.timestamps
    end
  end
end
于 2013-03-20T09:58:56.827 回答