Class: SimpleNestedSet::NestedSet
- Inherits:
-
ActiveRecord::Relation
- Object
- ActiveRecord::Relation
- SimpleNestedSet::NestedSet
- Defined in:
- lib/simple_nested_set/nested_set.rb
Instance Attribute Summary collapse
-
#node ⇒ Object
readonly
Returns the value of attribute node.
Class Method Summary collapse
Instance Method Summary collapse
- #attribute_names ⇒ Object
-
#denormalize! ⇒ Object
FIXME we don’t always want to call this on after_save, do we? it’s only relevant when either the structure or the slug has changed.
- #denormalize_level_query ⇒ Object
- #denormalize_path_query ⇒ Object
-
#init_as_node ⇒ Object
before validation set lft and rgt to the end of the tree.
-
#initialize(*args) ⇒ NestedSet
constructor
A new instance of NestedSet.
- #move_by_attributes(attributes) ⇒ Object
- #move_to(target, position) ⇒ Object
- #populate_associations(nodes) ⇒ Object
-
#prune_branch ⇒ Object
Prunes a branch off of the tree, shifting all of the elements on the right back to the left so the counts still work.
-
#reload ⇒ Object
reload left, right, and parent.
-
#same_scope?(other) ⇒ Boolean
Returns true if the node has the same scope as the given node.
- #save! ⇒ Object
Constructor Details
#initialize(*args) ⇒ NestedSet
Returns a new instance of NestedSet.
26 27 28 29 30 |
# File 'lib/simple_nested_set/nested_set.rb', line 26 def initialize(*args) super(node_class, node_class.arel_table) @node = args.first if args.size == 1 @where_values = self.class.scope(node).instance_variable_get(:@where_values) if node end |
Instance Attribute Details
#node ⇒ Object (readonly)
Returns the value of attribute node.
24 25 26 |
# File 'lib/simple_nested_set/nested_set.rb', line 24 def node @node end |
Class Method Details
.build_class(model, scopes) ⇒ Object
6 7 8 9 10 11 |
# File 'lib/simple_nested_set/nested_set.rb', line 6 def build_class(model, scopes) model.const_get(:NestedSet) rescue model.const_set(:NestedSet, Class.new(NestedSet)).tap do |node_class| node_class.node_class = model node_class.scope_names = Array(scopes).map { |s| s.to_s =~ /_id$/ ? s.to_sym : :"#{s}_id" } end end |
.scope(scope) ⇒ Object
13 14 15 |
# File 'lib/simple_nested_set/nested_set.rb', line 13 def scope(scope) scope.blank? ? node_class.scoped : node_class.where(scope_condition(scope)) end |
.scope_condition(scope) ⇒ Object
17 18 19 20 21 |
# File 'lib/simple_nested_set/nested_set.rb', line 17 def scope_condition(scope) scope_names.inject({}) do |c, name| c.merge(name => scope.respond_to?(name) ? scope.send(name) : scope[name]) end end |
Instance Method Details
#attribute_names ⇒ Object
58 59 60 |
# File 'lib/simple_nested_set/nested_set.rb', line 58 def attribute_names @attribute_names ||= node.attribute_names.select { |attribute| ATTRIBUTES.include?(attribute.to_sym) } end |
#denormalize! ⇒ Object
FIXME we don’t always want to call this on after_save, do we? it’s only relevant when either the structure or the slug has changed
41 42 43 44 45 46 |
# File 'lib/simple_nested_set/nested_set.rb', line 41 def denormalize! sql = [] sql << denormalize_level_query if node.has_attribute?(:level) sql << denormalize_path_query if node.has_attribute?(:path) update_all(sql.join(',')) unless sql.blank? end |
#denormalize_level_query ⇒ Object
98 99 100 101 102 103 104 105 |
# File 'lib/simple_nested_set/nested_set.rb', line 98 def denormalize_level_query query = arel_table.as(:l) query = query.project('count(id)'). where(query[:lft].lt(arel_table[:lft])). where(query[:rgt].gt(arel_table[:rgt])). where(where_clauses.map { |clause| clause.gsub(table_name, 'l') }) "level = (#{query.to_sql})" end |
#denormalize_path_query ⇒ Object
107 108 109 110 111 112 113 114 |
# File 'lib/simple_nested_set/nested_set.rb', line 107 def denormalize_path_query query = arel_table.as(:l) query = query.project("GROUP_CONCAT(slug, '/')"). where(query[:lft].lteq(arel_table[:lft])). where(query[:rgt].gteq(arel_table[:rgt])). where(where_clauses.map { |clause| clause.gsub(table_name, 'l') }) "path = (#{query.to_sql})" end |
#init_as_node ⇒ Object
before validation set lft and rgt to the end of the tree
72 73 74 75 |
# File 'lib/simple_nested_set/nested_set.rb', line 72 def init_as_node max_right = maximum(:rgt) || 0 node.lft, node.rgt = max_right + 1, max_right + 2 end |
#move_by_attributes(attributes) ⇒ Object
90 91 92 |
# File 'lib/simple_nested_set/nested_set.rb', line 90 def move_by_attributes(attributes) Move::ByAttributes.new(node, attributes).perform end |
#move_to(target, position) ⇒ Object
94 95 96 |
# File 'lib/simple_nested_set/nested_set.rb', line 94 def move_to(target, position) Move::ToTarget.new(node, target, position).perform end |
#populate_associations(nodes) ⇒ Object
62 63 64 65 66 67 68 69 |
# File 'lib/simple_nested_set/nested_set.rb', line 62 def populate_associations(nodes) node.children.target = nodes.select do |child| next unless child.parent_id == node.id nodes.delete(child) child.nested_set.populate_associations(nodes) child.parent = node end end |
#prune_branch ⇒ Object
Prunes a branch off of the tree, shifting all of the elements on the right back to the left so the counts still work.
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/simple_nested_set/nested_set.rb', line 79 def prune_branch if node.rgt && node.lft transaction do diff = node.rgt - node.lft + 1 delete_all(['lft > ? AND rgt < ?', node.lft, node.rgt]) update_all(['lft = (lft - ?)', diff], ['lft >= ?', node.rgt]) update_all(['rgt = (rgt - ?)', diff], ['rgt >= ?', node.rgt]) end end end |
#reload ⇒ Object
reload left, right, and parent
54 55 56 |
# File 'lib/simple_nested_set/nested_set.rb', line 54 def reload node.reload(:select => attribute_names.join(', ')) unless node.new_record? # FIXME reloading doesn't seem to work? end |
#same_scope?(other) ⇒ Boolean
Returns true if the node has the same scope as the given node
49 50 51 |
# File 'lib/simple_nested_set/nested_set.rb', line 49 def same_scope?(other) scope_names.all? { |scope| node.send(scope) == other.send(scope) } end |
#save! ⇒ Object
32 33 34 35 36 37 |
# File 'lib/simple_nested_set/nested_set.rb', line 32 def save! attributes = node.instance_variable_get(:@_nested_set_attributes) node.instance_variable_set(:@_nested_set_attributes, nil) move_by_attributes(attributes) unless attributes.blank? denormalize! end |