module Customize module Inherited def self.included base base.extend ClassMethods base.has_one :inherit_node, :class_name=>Customize::InheritNode.name, :as=>:node, :dependent=>:destroy base.after_create { |object| object.create_inherit_node :left=>0, :right=>1 } base.delegate :leaf?, :to=>:inherit_node base.before_destroy { |object| raise 'object should not have children when destroy' if object.inherit_node.children.size > 0 } end module ClassMethods def root joins(:inherit_node).where("parent_id is null") end def type_tree roots = root converter = proc {|items| out = items.collect { |item| {:id=>item.id,:label=>item.label,:inherit_node_id=>item.inherit_node.id, :children=>converter.call(item.children)} } } converter.call(roots) end end def parent inherit_node.parent_node.try(:node) end def children inherit_node.children.collect(&:node) end def label self.to_s end def inherit parent raise 'should be save first' if self.new_record? raise 'should be same class' if self.class != parent.class raise 'should not be self' if self.id == parent.id inherit_node.parent_id = parent.inherit_node.id right = parent.inherit_node.right InheritNode.where("right >= ?", inherit_node.left).update_all("right = right+2") inherit_node.left = right inherit_node.right = right + 1 inherit_node.save end def ascent_ids return [] if self.new_record? r = InheritNode.where("left < :left and right > :right and node_type = :type",:left=>inherit_node.left, :right=>inherit_node.right, :type=>self.class.name) r.pluck(:node_id) end def descent_ids return [] if self.new_record? r = InheritNode.where("left > :left and right < :right and node_type = :type", :left=>inherit_node.left, :right=>inherit_node.right, :type=>self.class.name) r.pluck(:node_id) end def ascents self.class.find ascent_ids end end end