Gem 多级类别的利器 awesome_nested_set

zangcw · 2013年12月05日 · 最后由 d4rkl0rd 回复于 2014年02月27日 · 6449 次阅读

应朋友的要求,从今天起,把用到的 gem 都写在 blog 上,即是给大家一个分享,也给自己一个记忆的地方。

原则就是,都是原创,可以少写,但是不帖大量自己没有搞懂的代码或者别人的观点。

今天用到了一个 gem 包叫做 awesome_nested_set

是一个专门处理多级 Model 嵌套的。使用二叉树算法,很精妙

用法

gem 'awesome_nested_set'
# gem 'awesome_nested_set', github: 'collectiveidea/awesome_nested_set' #on Rails 4

然后在你的 Migration 里面,要多级嵌套的地方写上

create_table :article_categories do |t|
  t.string :name
  t.integer :parent_id
  t.integer :lft
  t.integer :rgt
  t.integer :depth

  t.timestamps
end

然后在 model 里

acts_as_nested_set

OK 了,一个多级嵌套的模型已经搭建完毕了,简单吧?怎么用呢?

Model(such as article_category
- (Object) ancestors #所有的父节点(包括祖父节点)
- (Boolean) child? #是否是子节点?=有父节点
- (Object) descendants #所有的子节点(包括孙子节点)
- (Boolean) is_ancestor_of?(other) #是否是other的父辈
- (Boolean) is_descendant_of?(other) #是否是other的子辈
- (Boolean) is_or_is_ancestor_of?(other) #是否是other的父辈或自己
- (Boolean) is_or_is_descendant_of?(other) #是否是other的子辈或自己
- (Boolean) leaf? #是否是尾叶子节点?=没有子节点
- (Object) leaves #列出所有的叶子节点
- (Object) left #左边的兄弟编号(二叉树节点号,可不是id哟)
- (Object) left_sibling #左边的兄弟
- (Object) level #深度,0是root
- (Object) move_left #挪到左边兄弟的左边
- (Boolean) move_possible?(target) #能否挪到target的旁边(父子兄弟),如果是target的祖父就不可以
- (Object) move_right #挪到右边兄弟的右边
- (Object) move_to_child_of(node) #挪到node的子节点
- (Object) move_to_child_with_index(node, index) #挪到node的子节点,并且排序为index
- (Object) move_to_left_of(node) #挪到node的左边
- (Object) move_to_ordered_child_of(parent, order_attribute, ascending = true) #挪到parent下,按照order_attribute进行升序(ascending=true)或者降序(ascending=false)排序
- (Object) move_to_right_of(node) #挪到node的右边
- (Object) move_to_root #使自己脱离成为根节点
- (Object) parent #父节点
- (Object) right #右边的兄弟编号(同上)
- (Object) right_sibling #右边的兄弟
- (Object) root #返回所处的树的根节点
- (Boolean) root? #是否是根节点=没有父节点
- (Boolean) same_scope?(other) #这个不是很明白哦,以后搞懂再改
- (Object) self_and_ancestors #自己和所有的父辈
- (Object) self_and_descendants #自己和所有的子孙
- (Object) self_and_siblings #自己和所有的兄弟
- (Object) siblings #所有的兄弟
- (Object) to_text #以文本形式列出树,方便debug
* 1 #<ArticleCategory:0x007fa6815e6e90> (, 1, 8)
** 2 #<ArticleCategory:0x007fa6815e6ad0> (1, 2, 7)
*** 4 #<ArticleCategory:0x007fa6815e67b0> (2, 3, 4)
*** 3 #<ArticleCategory:0x007fa6815e64b8> (2, 5, 6)

通过 mysql 的 log 可以看出,每个方法都是一次读取数据库,不需要递归,不需要循环哦。 另外,可以加 callbacks 只需要在 acts_as_nested_set 后面加上一些参数即可

acts_as_nested_set  :before_add     => :do_before_add_stuff,
                    :after_add      => :do_after_add_stuff,
                    :before_remove  => :do_before_remove_stuff,
                    :after_remove   => :do_after_remove_stuff

好了,今天就到此吧,希望可以给大家帮助

转自我的 CSDN 博客

个人真实的使用经验,超过 100 万条数据,直接崩了,随便搞点啥就是慢查询,只好把它又去掉了

#1 楼 @Victor 这种多级的一般作为类别管理神马的,100W 数据比较夸张了,拿来用用还不错,算法值得学习

#2 楼 @zangcw 当时我也没想那么多,做了个回复功能,可以多级回复(可以给回复添加回复)。做完项目就回去修行,半年后回来一看,同事们说已经挺不住了,每个月新增几十万数据,撑到百万级别的时候就慢的不行,只好去掉了

@Victor 建了索引吗?

#4 楼 @winnie 这个插件去了之后,速度明显好转。但是因为评论消息的表字段较多,复杂查询较多,增加了索引,后来还做了其他的优化,效果还不错

这个就是给分类使用的,即便是淘宝的分类也就是在万级别的

7 楼 已删除

@zangcw 为什么提示 NoMethodError: undefined method `quoted_table_name' for ActiveRecord::AttributeMethods::Serialization::Type:Class

#8 楼 @d4rkl0rd 我没有遇到过这个提示,请问你的 ruby 版本和 gem 版本都是多少呢

@zangcw ruby1.9.x, awesome_nested_set 是最新的,不过我 rails 是 4.0.0 应该是对 4 支持不好。现在已经不用这东东了。呵呵。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号