Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 7454

Show
Ignore:
Timestamp:
09/11/07 03:25:59 (10 months ago)
Author:
david
Message:

Moved acts_as_tree into a plugin of the same name on the official Rails svn (closes #9514) [lifofifo]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r7453 r7454  
    11*SVN* 
     2 
     3* Moved acts_as_tree into a plugin of the same name on the official Rails svn #9514 [lifofifo] 
    24 
    35* Moved acts_as_nested_set into a plugin of the same name on the official Rails svn #9516 [josh] 
  • trunk/activerecord/lib/active_record.rb

    r7453 r7454  
    4444require 'active_record/transactions' 
    4545require 'active_record/timestamp' 
    46 require 'active_record/acts/tree' 
    4746require 'active_record/locking/optimistic' 
    4847require 'active_record/locking/pessimistic' 
     
    6463  include ActiveRecord::Transactions 
    6564  include ActiveRecord::Reflection 
    66   include ActiveRecord::Acts::Tree 
    6765  include ActiveRecord::Calculations 
    6866  include ActiveRecord::XmlSerialization 
  • trunk/activerecord/lib/active_record/acts/tree.rb

    r7366 r7454  
    1 module ActiveRecord 
    2   module Acts #:nodoc: 
    3     module Tree #:nodoc: 
    4       def self.included(base) 
    5         base.extend(ClassMethods) 
    6       end 
    7  
    8       # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children 
    9       # association. This requires that you have a foreign key column, which by default is called +parent_id+. 
    10       # 
    11       #   class Category < ActiveRecord::Base 
    12       #     acts_as_tree :order => "name" 
    13       #   end 
    14       # 
    15       #   Example: 
    16       #   root 
    17       #    \_ child1 
    18       #         \_ subchild1 
    19       #         \_ subchild2 
    20       # 
    21       #   root      = Category.create("name" => "root") 
    22       #   child1    = root.children.create("name" => "child1") 
    23       #   subchild1 = child1.children.create("name" => "subchild1") 
    24       # 
    25       #   root.parent   # => nil 
    26       #   child1.parent # => root 
    27       #   root.children # => [child1] 
    28       #   root.children.first.children.first # => subchild1 
    29       # 
    30       # In addition to the parent and children associations, the following instance methods are added to the class 
    31       # after calling <tt>acts_as_tree</tt>: 
    32       # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>) 
    33       # * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>) 
    34       # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>) 
    35       # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>) 
    36       module ClassMethods 
    37         # Configuration options are: 
    38         # 
    39         # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+) 
    40         # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet. 
    41         # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+). 
    42         def acts_as_tree(options = {}) 
    43           configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil } 
    44           configuration.update(options) if options.is_a?(Hash) 
    45  
    46           belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache] 
    47           has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy 
    48  
    49           class_eval <<-EOV 
    50             include ActiveRecord::Acts::Tree::InstanceMethods 
    51  
    52             def self.roots 
    53               find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}) 
    54             end 
    55  
    56             def self.root 
    57               find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}) 
    58             end 
    59           EOV 
    60         end 
    61       end 
    62  
    63       module InstanceMethods 
    64         # Returns list of ancestors, starting from parent until root. 
    65         # 
    66         #   subchild1.ancestors # => [child1, root] 
    67         def ancestors 
    68           node, nodes = self, [] 
    69           nodes << node = node.parent while node.parent 
    70           nodes 
    71         end 
    72  
    73         # Returns the root node of the tree. 
    74         def root 
    75           node = self 
    76           node = node.parent while node.parent 
    77           node 
    78         end 
    79  
    80         # Returns all siblings of the current node. 
    81         # 
    82         #   subchild1.siblings # => [subchild2] 
    83         def siblings 
    84           self_and_siblings - [self] 
    85         end 
    86  
    87         # Returns all siblings and a reference to the current node. 
    88         # 
    89         #   subchild1.self_and_siblings # => [subchild1, subchild2] 
    90         def self_and_siblings 
    91           parent ? parent.children : self.class.roots 
    92         end 
    93       end 
    94     end 
    95   end 
    96 end 
  • trunk/activerecord/test/associations/cascaded_eager_loading_test.rb

    r7081 r7454  
    66require 'fixtures/category' 
    77require 'fixtures/categorization' 
    8 require 'fixtures/mixin' 
    98require 'fixtures/company' 
    109require 'fixtures/topic' 
     
    5453  end 
    5554 
    56   def test_eager_association_loading_with_acts_as_tree 
    57     roots = TreeMixin.find(:all, :include=>"children", :conditions=>"mixins.parent_id IS NULL", :order=>"mixins.id") 
    58     assert_equal mixins(:tree_1, :tree2_1, :tree3_1), roots 
    59     assert_no_queries do 
    60       assert_equal 2, roots[0].children.size 
    61       assert_equal 0, roots[1].children.size 
    62       assert_equal 0, roots[2].children.size 
    63     end 
    64   end 
    65  
    6655  def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong 
    6756    firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id") 
     
    10493    end 
    10594  end 
    106  
    107   def test_eager_association_loading_with_recursive_cascading_three_levels_has_many 
    108     root_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:children=>{:children=>:children}}, :order => 'mixins.id') 
    109     assert_equal mixins(:recursively_cascaded_tree_4), assert_no_queries { root_node.children.first.children.first.children.first } 
    110   end 
    111  
    112   def test_eager_association_loading_with_recursive_cascading_three_levels_has_one 
    113     root_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:first_child=>{:first_child=>:first_child}}, :order => 'mixins.id') 
    114     assert_equal mixins(:recursively_cascaded_tree_4), assert_no_queries { root_node.first_child.first_child.first_child } 
    115   end 
    116  
    117   def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to 
    118     leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:parent=>{:parent=>:parent}}, :order => 'mixins.id DESC') 
    119     assert_equal mixins(:recursively_cascaded_tree_1), assert_no_queries { leaf_node.parent.parent.parent } 
    120   end 
    12195end 
    122  
    12396 
    12497require 'fixtures/vertex' 
  • trunk/activerecord/test/fixtures/mixins.yml

    r7453 r7454  
    1 # tree mixins 
    2 tree_1: 
    3   id: 1001 
    4   type: TreeMixin 
    5   parent_id: 
    6    
    7 tree_2: 
    8   id: 1002 
    9   type: TreeMixin 
    10   parent_id: 1001 
    11  
    12 tree_3: 
    13   id: 1003 
    14   type: TreeMixin   
    15   parent_id: 1002 
    16  
    17 tree_4: 
    18   id: 1004 
    19   type: TreeMixin   
    20   parent_id: 1001 
    21  
    22 tree2_1: 
    23   id: 1005 
    24   type: TreeMixin 
    25   parent_id: 
    26  
    27 tree3_1: 
    28   id: 1006 
    29   type: TreeMixin 
    30   parent_id: 
    31  
    32 tree_without_order_1: 
    33   id: 1101 
    34   type: TreeMixinWithoutOrder 
    35   parent_id: 
    36  
    37 tree_without_order_2: 
    38   id: 1100 
    39   type: TreeMixinWithoutOrder 
    40   parent_id: 
    41  
    42 recursively_cascaded_tree_1: 
    43   id: 5005 
    44   type: RecursivelyCascadedTreeMixin 
    45   parent_id: 
    46  
    47 recursively_cascaded_tree_2: 
    48   id: 5006 
    49   type: RecursivelyCascadedTreeMixin 
    50   parent_id: 5005 
    51  
    52 recursively_cascaded_tree_3: 
    53   id: 5007 
    54   type: RecursivelyCascadedTreeMixin 
    55   parent_id: 5006 
    56  
    57 recursively_cascaded_tree_4: 
    58   id: 5008 
    59   type: RecursivelyCascadedTreeMixin 
    60   parent_id: 5007 
    61  
    62  
    631# Nested set mixins 
    642 
     
    664set_<%= counter %>: 
    675  id: <%= counter+3000 %> 
    68   type: NestedSet 
    696<% end %> 
    707 
  • trunk/activerecord/test/mixin_test.rb

    r7444 r7454  
    22require 'active_record/acts/tree' 
    33require 'active_record/acts/nested_set' 
    4 require 'fixtures/mixin' 
     4 
     5class Mixin < ActiveRecord::Base 
     6end 
    57 
    68# Let us control what Time.now returns for the TouchTest suite 
     
    2123end 
    2224 
    23  
    24 class TreeTest < Test::Unit::TestCase 
    25   fixtures :mixins 
    26  
    27   def test_children 
    28     assert_equal mixins(:tree_1).children, mixins(:tree_2, :tree_4) 
    29     assert_equal mixins(:tree_2).children, [mixins(:tree_3)] 
    30     assert_equal mixins(:tree_3).children, [] 
    31     assert_equal mixins(:tree_4).children, [] 
    32   end 
    33  
    34   def test_parent 
    35     assert_equal mixins(:tree_2).parent, mixins(:tree_1) 
    36     assert_equal mixins(:tree_2).parent, mixins(:tree_4).parent 
    37     assert_nil mixins(:tree_1).parent 
    38   end 
    39  
    40   def test_delete 
    41     assert_equal 6, TreeMixin.count 
    42     mixins(:tree_1).destroy 
    43     assert_equal 2, TreeMixin.count 
    44     mixins(:tree2_1).destroy 
    45     mixins(:tree3_1).destroy 
    46     assert_equal 0, TreeMixin.count 
    47   end 
    48  
    49   def test_insert 
    50     @extra = mixins(:tree_1).children.create 
    51  
    52     assert @extra 
    53  
    54     assert_equal @extra.parent, mixins(:tree_1) 
    55  
    56     assert_equal 3, mixins(:tree_1).children.size 
    57     assert mixins(:tree_1).children.include?(@extra) 
    58     assert mixins(:tree_1).children.include?(mixins(:tree_2)) 
    59     assert mixins(:tree_1).children.include?(mixins(:tree_4)) 
    60   end 
    61  
    62   def test_ancestors 
    63     assert_equal [], mixins(:tree_1).ancestors 
    64     assert_equal [mixins(:tree_1)], mixins(:tree_2).ancestors 
    65     assert_equal mixins(:tree_2, :tree_1), mixins(:tree_3).ancestors 
    66     assert_equal [mixins(:tree_1)], mixins(:tree_4).ancestors 
    67     assert_equal [], mixins(:tree2_1).ancestors 
    68     assert_equal [], mixins(:tree3_1).ancestors 
    69   end 
    70  
    71   def test_root 
    72     assert_equal mixins(:tree_1), TreeMixin.root 
    73     assert_equal mixins(:tree_1), mixins(:tree_1).root 
    74     assert_equal mixins(:tree_1), mixins(:tree_2).root 
    75     assert_equal mixins(:tree_1), mixins(:tree_3).root 
    76     assert_equal mixins(:tree_1), mixins(:tree_4).root 
    77     assert_equal mixins(:tree2_1), mixins(:tree2_1).root 
    78     assert_equal mixins(:tree3_1), mixins(:tree3_1).root 
    79   end 
    80  
    81   def test_roots 
    82     assert_equal mixins(:tree_1, :tree2_1, :tree3_1), TreeMixin.roots 
    83   end 
    84  
    85   def test_siblings 
    86     assert_equal mixins(:tree2_1, :tree3_1), mixins(:tree_1).siblings 
    87     assert_equal [mixins(:tree_4)], mixins(:tree_2).siblings 
    88     assert_equal [], mixins(:tree_3).siblings 
    89     assert_equal [mixins(:tree_2)], mixins(:tree_4).siblings 
    90     assert_equal mixins(:tree_1, :tree3_1), mixins(:tree2_1).siblings 
    91     assert_equal mixins(:tree_1, :tree2_1), mixins(:tree3_1).siblings 
    92   end 
    93  
    94   def test_self_and_siblings 
    95     assert_equal mixins(:tree_1, :tree2_1, :tree3_1), mixins(:tree_1).self_and_siblings 
    96     assert_equal mixins(:tree_2, :tree_4), mixins(:tree_2).self_and_siblings 
    97     assert_equal [mixins(:tree_3)], mixins(:tree_3).self_and_siblings 
    98     assert_equal mixins(:tree_2, :tree_4), mixins(:tree_4).self_and_siblings 
    99     assert_equal mixins(:tree_1, :tree2_1, :tree3_1), mixins(:tree2_1).self_and_siblings 
    100     assert_equal mixins(:tree_1, :tree2_1, :tree3_1), mixins(:tree3_1).self_and_siblings 
    101   end 
    102 end 
    103  
    104 class TreeTestWithoutOrder < Test::Unit::TestCase 
    105   fixtures :mixins 
    106  
    107   def test_root 
    108     assert mixins(:tree_without_order_1, :tree_without_order_2).include?(TreeMixinWithoutOrder.root) 
    109   end 
    110  
    111   def test_roots 
    112     assert_equal [], mixins(:tree_without_order_1, :tree_without_order_2) - TreeMixinWithoutOrder.roots 
    113   end 
    114 end 
    11525 
    11626class TouchTest < Test::Unit::TestCase 
     
    17181    Mixin.record_timestamps = false 
    17282 
    173     assert_nil mixins(:tree_1).updated_at 
    174     mixins(:tree_1).save 
    175     assert_nil mixins(:tree_1).updated_at 
     83    assert_nil mixins(:set_1).updated_at 
     84    mixins(:set_1).save 
     85    assert_nil mixins(:set_1).updated_at 
    17686 
    17787    Mixin.record_timestamps = true 
     
    17989 
    18090end 
    181  
    182  
    183  
    184