From b0630673213ed2bee99883cb9197ddf6457a3fac Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 9 Sep 2005 08:01:44 +0000 Subject: Added the instance methods #root and #ancestors on acts_as_tree and fixed siblings to not include the current node #2142, #2140 [coffee2code] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2163 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/CHANGELOG | 2 ++ activerecord/lib/active_record/acts/tree.rb | 38 +++++++++++++++++++++-------- activerecord/test/fixtures/mixins.yml | 12 ++++++++- activerecord/test/mixin_test.rb | 30 +++++++++++++++++++++-- 4 files changed, 69 insertions(+), 13 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 10b562362e..e6d6c78de4 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Added the instance methods #root and #ancestors on acts_as_tree and fixed siblings to not include the current node #2142, #2140 [coffee2code] + * Fixed that Active Record would call SHOW FIELDS twice (or more) for the same model when the cached results were available #1947 [sd@notso.net] * Added log_level and use_silence parameter to ActiveRecord::Base.benchmark. The first controls at what level the benchmark statement will be logged (now as debug, instead of info) and the second that can be passed false to include all logging statements during the benchmark block/ diff --git a/activerecord/lib/active_record/acts/tree.rb b/activerecord/lib/active_record/acts/tree.rb index 2463a1209a..5fc7ddf41c 100644 --- a/activerecord/lib/active_record/acts/tree.rb +++ b/activerecord/lib/active_record/acts/tree.rb @@ -16,16 +16,23 @@ module ActiveRecord # Example : # root # \_ child1 - # \_ sub-child1 + # \_ subchild1 + # \_ subchild2 # # root = Category.create("name" => "root") - # child1 = root.children.create("name" => "child1") - # subchild1 = child1.children.create("name" => "subchild1") + # child1 = root.children.create("name" => "child1") + # subchild1 = child1.children.create("name" => "subchild1") # - # root.parent # => nil + # root.parent # => nil # child1.parent # => root # root.children # => [child1] # root.children.first.children.first # => subchild1 + # + # In addition to the parent and children associations, the following instance methods are added to the class + # after specifying the act: + # * siblings: Return all the children of the parent excluding the current node ([ subchild2 ] when called from subchild1) + # * ancestors: Returns all the ancestors of the current node ([child1, root] when called from subchild2) + # * root: Returns the root of the current node (root when called from subchild2) module ClassMethods # Configuration options are: # @@ -48,15 +55,26 @@ module ActiveRecord end END + # Returns list of ancestors, starting from parent until root. + # + # subchild1.ancestors # => [child1, root] + define_method(:ancestors) do + node, nodes = self, [] + nodes << node = node.parent until not node.has_parent? + nodes + end + + define_method(:root) do + node = self + node = node.parent until not node.has_parent? + node + end + define_method(:siblings) do - if parent - self.class.find(:all, :conditions => [ "#{configuration[:foreign_key]} = ?", parent.id ], :order => configuration[:order]) - else - self.class.roots - end + ( has_parent? ? parent.children : self.class.roots ) - [self] end end end end end -end \ No newline at end of file +end diff --git a/activerecord/test/fixtures/mixins.yml b/activerecord/test/fixtures/mixins.yml index 9f8e1ee8de..1d990c2e8e 100644 --- a/activerecord/test/fixtures/mixins.yml +++ b/activerecord/test/fixtures/mixins.yml @@ -2,7 +2,7 @@ tree_1: id: 1001 type: TreeMixin - parent_id: 0 + parent_id: tree_2: id: 1002 @@ -18,6 +18,16 @@ tree_4: id: 1004 type: TreeMixin parent_id: 1001 + +tree2_1: + id: 1005 + type: TreeMixin + parent_id: + +tree3_1: + id: 1006 + type: TreeMixin + parent_id: # List mixins diff --git a/activerecord/test/mixin_test.rb b/activerecord/test/mixin_test.rb index a6f759432f..dd29d94ab1 100644 --- a/activerecord/test/mixin_test.rb +++ b/activerecord/test/mixin_test.rb @@ -214,6 +214,13 @@ class TreeTest < Test::Unit::TestCase assert_equal mixins(:tree_4).children, [] end + def test_has_parent + assert_equal false, mixins(:tree_1).has_parent? + assert_equal true, mixins(:tree_2).has_parent? + assert_equal true, mixins(:tree_3).has_parent? + assert_equal true, mixins(:tree_4).has_parent? + end + def test_parent assert_equal mixins(:tree_2).parent, mixins(:tree_1) assert_equal mixins(:tree_2).parent, mixins(:tree_4).parent @@ -221,11 +228,14 @@ class TreeTest < Test::Unit::TestCase end def test_delete - assert_equal 4, TreeMixin.count + assert_equal 6, TreeMixin.count mixins(:tree_1).destroy + assert_equal 2, TreeMixin.count + mixins(:tree2_1).destroy + mixins(:tree3_1).destroy assert_equal 0, TreeMixin.count end - + def test_insert @extra = mixins(:tree_1).children.create @@ -239,6 +249,22 @@ class TreeTest < Test::Unit::TestCase assert mixins(:tree_1).children.include?(mixins(:tree_4)) end + def test_root + assert_equal mixins(:tree_1), TreeMixin.root + end + + def test_roots + assert_equal [mixins(:tree_1), mixins(:tree2_1), mixins(:tree3_1)], TreeMixin.roots + end + + def test_siblings + assert_equal [mixins(:tree2_1), mixins(:tree3_1)], mixins(:tree_1).siblings + assert_equal [mixins(:tree_4)], mixins(:tree_2).siblings + assert_equal [], mixins(:tree_3).siblings + assert_equal [mixins(:tree_2)], mixins(:tree_4).siblings + assert_equal [mixins(:tree_1), mixins(:tree3_1)], mixins(:tree2_1).siblings + assert_equal [mixins(:tree_1), mixins(:tree2_1)], mixins(:tree3_1).siblings + end end class TouchTest < Test::Unit::TestCase -- cgit v1.2.3