我想与我的'产品'类创建一个recusive relationsip。我可以将一种产品作为其他产品的母产品。我的问题是如何在我的模型中创建这种关系?
这会是正确的吗?
has_many :products
belongs_to :product
答案 0 :(得分:40)
逻辑您提出的解决方案没有任何问题。但是,您可能需要执行以下操作:
belongs_to :parent, class_name: "Product", foreign_key: "parent_id"
has_many :children, class_name: "Product", foreign_key: "parent_id"
您基本上存储了一个“树”,其中一个产品位于顶部,而子产品的分支位于下方,可能有很多层次。
您的示例中的策略称为Adjacency List。很容易找到任何给定记录的直接父级和直接后代。然而,获得所有后代(包括后代的后代)可能很困难,并且树越深越难。
常用的替代方法是Nested Set,其中每条记录将有关对象的信息存储到它的“左”和“右”。这允许您构建一个树,无论多大,很快(或者至少在单个查询中有效)。但是,它更复杂,插入记录通常意味着必须重新计算并更新您插入的记录右侧的所有记录。
第三个选项(可以说是一种中间地带)正在使用Path Enumeration,其中对象将整个路径存储在树中。所以,给这样一棵树:
A
/ \
B C
|
D
A
将有一个空白路径(没有父级),B
和C
将拥有路径A
,D
将拥有路径{{ 1}}。使用此解决方案,大多数插入操作相对便宜,查询非常简单。然而,它在树中仍然相当复杂和移动的物体可能会变得昂贵。
还有其他选项,例如Closure Tables。
如果简单的邻接列表适合您的需求,那么请继续使用。这绝对是最简单和最容易理解的。有些宝石可以实现嵌套集,也可能用于其他一些树模式,所以如果你走这条路,你就不必自己做所有繁重的工作。