A Nested Set is similar to a tree from ActsAsTree. However the nested set allows building of the entire hierarchy at once instead of querying each nodes children, and their children. When destroying an object, a before_destroy trigger prunes the rest of the branch of object under the current object.
create table nested_objects ( id int(11) unsigned not null auto_increment, parent_id int(11), lft int(11), rgt int(11), name varchar(32), primary key (id) );
class NestedObject < ActiveRecord::Base acts_as_nested_set end
下面就使用acts_as_nested_set来生成一个Ext的Tree。
比如生成如下的树:
root |_ Child 1 | |_ Child 1.1 | |_ Child 1.2 |_ Child 2 |_ Child 2.1 |_ Child 2.2
先来看一下对上面的树的一个图形化的解释:
这图还是比较清除的,请理解横线中的1到14这些数字,对应这个树,我们可能会有下面的数据:
这个也就是SQL脚本中的的lft和rgt的解释。rails ExtTree
ruby script/plugin install acts_as_nested_set
ruby script/generate resource Category parent_id:integer lft:integer rgt:integer text:string
class Category < ActiveRecord::Base acts_as_nested_set end
class CategoriesController < ApplicationController def index(id = params[:node]) respond_to do |format| format.html # render static index.html.erb format.json { render :json => Category.find_children(id) } end end end
#首先先得到树的根节点,再根据传过来的id找到根的子节点 def self.find_children(start_id = nil) start_id.to_i == 0 ? root_nodes : find(start_id).direct_children end #如果parent_id为空,则为树的根节点 def self.root_nodes find(:all, :conditions => 'parent_id IS NULL') end
def leaf unknown? || children_count == 0 end def to_json_with_leaf(options = {}) self.to_json_without_leaf(options.merge(:methods => :leaf)) end alias_method_chain :to_json, :leaf
alias_method :old_method_name :new_method_name
alias_method :old_method_name :new_method_name alias_method :new_method_name :old_method_name
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html;charset=UTF-8"/> <title>Rails Ext Tree</title> <%= stylesheet_link_tag "../ext/resources/css/ext-all.css" %> <%= javascript_include_tag :defaults %> <%= javascript_include_tag "../ext/adapter/prototype/ext-prototype-adapter.js" %> <%= javascript_include_tag "../ext/ext-all.js" %> </head> <body> <div id="category-tree" style="padding:20px"></div> <% javascript_tag do -%> Ext.onReady(function(){ root = new Ext.tree.AsyncTreeNode({ text: 'Invisible Root', id:'0' }); new Ext.tree.TreePanel({ loader: new Ext.tree.TreeLoader({ url:'/categories', requestMethod:'GET', baseParams:{format:'json'} }), renderTo:'category-tree', root: root, rootVisible:false }); root.expand(); }); <% end -%> </body> </html>
root = Category.create(:text => 'Root') root.add_child(c1 = Category.create(:text => 'Child 1')) c1.add_child(Category.create(:text => 'Child 1.1')) c1.add_child(Category.create(:text => 'Child 1.2')) root.add_child(c2 = Category.create(:text => 'Child 2')) c2.add_child(c21 = Category.create(:text => 'Child 2.1')) c2.add_child(c21 = Category.create(:text => 'Child 2.2'))