Commit 8923158bf6bc9f7ae4b485381b3cde99de123b1d

Authored by Braulio Bhavamitra
Committed by Braulio Bhavamitra
1 parent 95ebdaf6

Improve migration performance

db/migrate/20120820142056_add_ancestry_to_categories.rb
@@ -2,10 +2,7 @@ class AddAncestryToCategories < ActiveRecord::Migration @@ -2,10 +2,7 @@ class AddAncestryToCategories < ActiveRecord::Migration
2 def self.up 2 def self.up
3 add_column :categories, :ancestry, :text 3 add_column :categories, :ancestry, :text
4 4
5 - Category.all.each do |category|  
6 - category.set_ancestry  
7 - category.save!  
8 - end 5 + Category.build_ancestry
9 end 6 end
10 7
11 def self.down 8 def self.down
lib/acts_as_filesystem.rb
1 module ActsAsFileSystem 1 module ActsAsFileSystem
2 2
3 - module ClassMethods 3 + module ActsMethods
4 4
5 # Declares the ActiveRecord model to acts like a filesystem: objects are 5 # Declares the ActiveRecord model to acts like a filesystem: objects are
6 # arranged in a tree (liks acts_as_tree), and . The underlying table must 6 # arranged in a tree (liks acts_as_tree), and . The underlying table must
@@ -14,11 +14,12 @@ module ActsAsFileSystem @@ -14,11 +14,12 @@ module ActsAsFileSystem
14 # the parent, a "/" and the slug of the object) 14 # the parent, a "/" and the slug of the object)
15 # * children_count - a cache of the number of children elements. 15 # * children_count - a cache of the number of children elements.
16 def acts_as_filesystem 16 def acts_as_filesystem
17 - include ActsAsFileSystem::InstanceMethods  
18 -  
19 # a filesystem is a tree 17 # a filesystem is a tree
20 acts_as_tree :counter_cache => :children_count 18 acts_as_tree :counter_cache => :children_count
21 19
  20 + include InstanceMethods
  21 + extend ClassMethods
  22 +
22 before_create :set_path 23 before_create :set_path
23 before_save :set_ancestry 24 before_save :set_ancestry
24 after_update :update_children_path 25 after_update :update_children_path
@@ -26,6 +27,20 @@ module ActsAsFileSystem @@ -26,6 +27,20 @@ module ActsAsFileSystem
26 27
27 end 28 end
28 29
  30 + module ClassMethods
  31 +
  32 + def build_ancestry(parent_id = nil, ancestry = '')
  33 + self.base_class.all(:conditions => {:parent_id => parent_id}).each do |node|
  34 + node.ancestry = ancestry
  35 + node.save :run_callbacks => false
  36 +
  37 + build_ancestry node.id, (ancestry.empty? ? "#{node.formatted_ancestry_id}" :
  38 + "#{ancestry}#{node.ancestry_sep}#{node.formatted_ancestry_id}")
  39 + end
  40 + end
  41 +
  42 + end
  43 +
29 module InstanceMethods 44 module InstanceMethods
30 45
31 # used to know when to trigger batch renaming 46 # used to know when to trigger batch renaming
@@ -44,25 +59,35 @@ module ActsAsFileSystem @@ -44,25 +59,35 @@ module ActsAsFileSystem
44 path.split(/\//) 59 path.split(/\//)
45 end 60 end
46 61
  62 + def ancestry_column
  63 + 'ancestry'
  64 + end
  65 + def ancestry_sep
  66 + '.'
  67 + end
47 def has_ancestry? 68 def has_ancestry?
48 - self.class.column_names.include? 'ancestry' 69 + self.class.column_names.include? self.ancestry_column
49 end 70 end
50 - def ancestry  
51 - self['ancestry'] 71 +
  72 + def formatted_ancestry_id
  73 + "%010d" % self.id if self.id
52 end 74 end
53 - def ancestry=(value)  
54 - self['ancestry'] = value 75 +
  76 + def ancestry
  77 + self[ancestry_column]
55 end 78 end
56 - # get the serialized tree from database column 'ancetry'  
57 - # and convert it to an array  
58 - def ancestry_ids 79 + def ancestor_ids
59 return nil if !has_ancestry? or ancestry.nil? 80 return nil if !has_ancestry? or ancestry.nil?
60 - @ancestry_ids ||= ancestry.split('.').map{ |id| id.to_i } 81 + @ancestor_ids ||= ancestry.split(ancestry_sep).map{ |id| id.to_i }
  82 + end
  83 +
  84 + def ancestry=(value)
  85 + self[ancestry_column] = value
61 end 86 end
62 def set_ancestry 87 def set_ancestry
63 return unless self.has_ancestry? 88 return unless self.has_ancestry?
64 if self.ancestry.nil? or (new_record? or parent_id_changed?) or recalculate_path 89 if self.ancestry.nil? or (new_record? or parent_id_changed?) or recalculate_path
65 - self.ancestry = self.hierarchy[0...-1].map{ |p| "%010d" % p.id }.join('.') 90 + self.ancestry = self.hierarchy(true)[0...-1].map{ |p| p.formatted_ancestry_id }.join(ancestry_sep)
66 end 91 end
67 end 92 end
68 93
@@ -107,7 +132,7 @@ module ActsAsFileSystem @@ -107,7 +132,7 @@ module ActsAsFileSystem
107 self.hierarchy.first 132 self.hierarchy.first
108 end 133 end
109 def top_ancestor_id 134 def top_ancestor_id
110 - self.ancestry_ids.first 135 + self.ancestor_ids.first
111 end 136 end
112 137
113 # returns the full hierarchy from the top-level item to this one. For 138 # returns the full hierarchy from the top-level item to this one. For
@@ -123,9 +148,9 @@ module ActsAsFileSystem @@ -123,9 +148,9 @@ module ActsAsFileSystem
123 if @hierarchy.nil? 148 if @hierarchy.nil?
124 @hierarchy = [] 149 @hierarchy = []
125 150
126 - if ancestry_ids  
127 - objects = self.class.base_class.all(:conditions => {:id => ancestry_ids})  
128 - ancestry_ids.each{ |id| @hierarchy << objects.find{ |t| t.id == id } } 151 + if !reload and !recalculate_path and ancestor_ids
  152 + objects = self.class.base_class.all(:conditions => {:id => ancestor_ids})
  153 + ancestor_ids.each{ |id| @hierarchy << objects.find{ |t| t.id == id } }
129 @hierarchy << self 154 @hierarchy << self
130 else 155 else
131 item = self 156 item = self
@@ -207,5 +232,5 @@ module ActsAsFileSystem @@ -207,5 +232,5 @@ module ActsAsFileSystem
207 end 232 end
208 end 233 end
209 234
210 -ActiveRecord::Base.extend ActsAsFileSystem::ClassMethods 235 +ActiveRecord::Base.extend ActsAsFileSystem::ActsMethods
211 236