2013-03-01 56 views
2

我想分类多棵树中的对象以反映它们的特征并在其上构建导航。Rails:单个项目的多棵树

因此,考虑到以下树:

Category1 
-Category-1-1 
-Category-1-2 

Category2 
-Category-2-1 
-Category-2-2 
--Category-2-2-1 

的对象可以是例如属于类别1-2和类别2-2-1。

我们的目标是能够从数据库中获取所有对象

  • 属于某一类别
  • 属于某一类或它的decendants

更实际例如:

类别可能具有“工具>园艺工具>刀具”的层次结构。

第二类:“硬物体>金属物体>小金属物体”

一个对象的修枝剪'将被分类为属于“刀具”,以及“小金属物体”。

我希望能够

  • 检索所有的“园艺工具” - >“修枝”
  • 检索“园艺工具”的所有类别的孩子 - >“刀”
  • 检索所有“硬物 - >‘修枝’
  • 检索所有‘硬物’,同时也是‘刀’ - >‘修枝’
  • 检索所有的‘软目标’,同时也是‘刀’ - > [] 任何指针?我简要地看了一下closure_tree,awesome_nested_sets等,但我不确定它们是否匹配。

回答

4

我只是做了这一点,我选择不使用的祖先,但closure_tree因为笔者说,这是速度更快,我同意他的观点。知道你需要在类别(我喜欢每次添加多个单个对象时调用标签)和对象之间的`has_and_belongs_to_many'。

现在的发现者,坏消息是没有你自己的自定义查询,你可能无法做到这一点。使用宝石的方法,你会做这样的事情:

Item.joins(:tags).where(tags: {id: self_and_descendant_ids }) 

的代码是干净的,它执行两个查询,一个用于descendant_ids,另一个中的对象。这个略有变化,应该给你除了最后一个以外所需要的东西。这是一个艰难的,我没有实现它(我在这个过程中)。

现在,您必须在两个(查询计数:2),这些标记中的所有项目(查询计数:4)和相交处呼叫tag.self_and_ancestor_ids。在此之后,需要进行一些严重的重构。我认为我们需要编写SQL来减少查询次数,我不认为Rails查询接口就够了。

我选择* closure_tree *的另一个原因是parent_id的使用,所有兄弟分享它(就像任何其他Rails关联一样),因此它更容易与其他宝石(例如排序模型)进行交互。

+0

我真的很喜欢你的答案,但已经奖励其他用户的赏金,希望激励她/他成为SO的更积极的用户。不过,我接受你的答案。 – 2013-03-15 08:52:28

+0

我很高兴能帮到你! – Leito 2013-03-15 15:21:34

2

我想你可以去一棵树宝石,我个人喜欢Ancestry。然后为每个类别建立一个关联,使其拥有多个对象,每个对象可以属于多个类别。

你有没有偶然发现任何问题,或者你只是在研究你的选择?

+0

也许我误解了Ancestry的工作方式,但是它不仅仅允许我将物体放在一棵树上吗? – 2013-03-08 14:13:23

+0

是的,我要做的是在树结构中组织类别,然后将每个节点(类别)与要分类的对象连接起来。 – 2013-03-08 15:07:46

5

请注意,这里的代码都是伪代码。

我会用ancestry gem,并用三个模型类来模拟你的数据。 通过这种方式,您的数据已经过规范化,并且是一个很好的基础。

Category - ancestry tree 
    has_may Memberships 
    has_may Products through Memberships 

Membership 
    belongs_to Category 
    belongs_to Products 

Products 
    has_may Memberships 
    has_may Categories through Memberships 

从那里你需要弄清楚如何有效地执行equerries。 我这样做的方法是了解如何使用SQL执行此操作,然后弄清楚如何使用activercord的DSL来表示查询。

一些资源:

查询示例:

查找类别。

Category.find(category_id)

找到一个类别,包括它的指定类别内的产品。

Category.find(category_id).join(:memberships => :products)

查找类别的子树IND包括产品

Category.subtree_of(category_id).join(:memberships => :products)

查找所有类别中的产品属于。

Product.find(product_id).categories

+0

谢谢你提供一个非常全面的答案。 – 2013-03-15 08:55:18