gpt4 book ai didi

ruby-on-rails - 在 Ruby on Rails 中实现复合模式

转载 作者:行者123 更新时间:2023-12-02 11:35:46 25 4
gpt4 key购买 nike

我正在尝试实现典型的 gof 复合模式:

example class diagram

稍后查询时我有点迷失了。例如,是否有一种很好的方法来查询所有没有任何祖先的复合 Material ?

我最初的想法是用 ActiveRecord 创建类似的东西

class Component < ActiveRecord::Base
belongs_to :childrenable, :polymorphic => true
has_and_belongs_to_many: composites
end

class Leaf < ActiveRecord::Base
has_many: components, :as => :childrenable
end

class Composite < ActiveRecord::Base
has_many: components, :as => :childrenable
has_and_belongs_to_many :components
end

这行得通吗?我将如何构建这样的列表(在 f.ex 稍后的 View 中)?:

CompositeA  
->Item
->CompositeB
->ItemA
->CompositeC
->ItemA
->ItemB

当谈到查询时我有点迷失。对于这个问题有什么最佳实践吗?

最佳答案

在实际解决方案之前有几个方面:

  • 该图和您的示例在一个非常关键的方面有所不同。该图表明 Container 和 Children 之间的关系是一对多。然而你的例子表明它是多对多的。
  • 这两种情况都可以主要使用单个模型来解决。

多对多

可以使用与其自身的多对多关系来解决。

型号

class Component < ActiveRecord::Base
# Add as many attributes you need
attr_accessible :name

has_and_belongs_to_many :children,
:class_name => "Component",
:join_table => "children_containers",
:foreign_key => "container_id",
:association_foreign_key => "child_id"

has_and_belongs_to_many :containers,
:class_name => "Component",
:join_table => "children_containers",
:foreign_key => "child_id",
:association_foreign_key => "container_id"

# All Components that do not belong to any container
scope :roots, -> {where("not exists (select * from children_containers where child_id=components.id)")}

# All Components that have no children
scope :leaves, -> {where("not exists (select * from children_containers where container_id=components.id)")}

# Is this Component at root level
def root?
self.containers.empty?
end

# Is this Component at leaf level
def leaf?
self.children.empty?
end

# Notice the recursive call to traverse the Component hierarchy
# Similarly, it can be written to output using nested <ul> and <li>s as well.
def to_s(level=0)
"#{' ' * level}#{name}\n" + children.map {|c| c.to_s(level + 1)}.join
end
end

迁移

class CreateComponents < ActiveRecord::Migration
def change
create_table :components do |t|
t.string :name

t.timestamps
end

create_table :children_containers, :id => false do |t|
t.references :child
t.references :container
end

add_index :children_containers, :child_id
add_index :children_containers, [:container_id, :child_id], :unique => true
end
end

示例代码

["R1", "R2", "L1", "L2", "C1", "C2", "C3"].each {|n| Component.create(:name => n)}

[
["R1", "C1"],
["R2", "C2"],
["R1", "C3"],
["R2", "C3"],
["C1", "L1"],
["C2", "L2"],
["C3", "L1"],
["C3", "L2"]
].each {|pair| p,c=pair; Component.find_by_name(p).children << Component.find_by_name(c)}

puts Component.roots.map(&:name).to_s
# ["R1", "R2"]

puts Component.leaves.map(&:name).to_s
# ["L1", "L2"]

puts Component.find_by_name("R1").to_s
# R1
# C1
# L1
# C3
# L1
# L2

一对多

在这种情况下要简单得多。在组件模型中使用 Ancestry ( https://github.com/stefankroes/ancestry )。它将提供所需的所有操作。或者,可以使用acts_as_tree 代替Ancestry。

如果您需要示例代码,请告诉我。

关于ruby-on-rails - 在 Ruby on Rails 中实现复合模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17603142/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com