Permalink
Browse files

Merge remote-tracking branch 'ckdake/master'

  • Loading branch information...
2 parents 770f2e3 + 9effe4c commit 5027924e03d01f32bc1627fe2d22bda57c3432fd @iconoclast committed Jul 23, 2011
Showing with 53 additions and 1 deletion.
  1. +2 −1 .gitignore
  2. +20 −0 README.rdoc
  3. +13 −0 lib/ancestry/instance_methods.rb
  4. +18 −0 test/has_ancestry_test.rb
View
@@ -1,6 +1,7 @@
+.rvmrc
doc
*.gem
**/*.log
**/*.db
test/database.yml
-coverage
+coverage
View
@@ -221,6 +221,26 @@ For example, from IRB:
Additionally, if you think something is wrong with your depth cache:
>> TreeNode.rebuild_depth_cache!
+
+= Copying
+
+Ancestry provides a method to clone a tree, optionally replacing attributes and/or preserving a reference to the parent. This allows the creation of structures that use a 'default' tree and make copies of it. Example
+
+ class Category < ActiveRecord::Base
+ belongs_to :project
+ belongs_to :source_category, :class_name => "Category"
+ scope :defaults, where(:project_id => nil)
+
+ def self.import_from_defaults_for(project)
+ defaults.roots.all.each do |root|
+ root.clone_with_modifications!({:project_id => project.id}, nil, :source_category_id)
+ end
+ end
+
+ class Project < ActiveRecord::Base
+ has_many :categories, :dependent => :destroy
+ after_create Proc.new { |p| Category.import_from_defaults_for(self) }
+ end
= Tests
@@ -55,6 +55,19 @@ def apply_orphan_strategy
end
end
end
+
+ # Clone an object and all children
+ # => replacing values with those from attributes if present
+ # => setting parent to new parent if present
+ # => setting the "original_id_field_name" if present to the id of the original object
+ def clone_with_modifications!(attributes = nil, parent = nil, original_id_field_name = nil)
+ clone = self.class.create!(self.attributes.merge(:ancestry => nil).merge(attributes))
+ clone.send("#{original_id_field_name}=", self.id) if original_id_field_name
+ clone.parent = parent
+ self.children.each { |child| child.clone_with_modifications!(attributes, clone, original_id_field_name) }
+ clone.save!
+ clone
+ end
# The ancestry value for this record's children
def child_ancestry
View
@@ -704,4 +704,22 @@ def test_sort_by_ancestry
assert_equal [n1, n2, n4, n3, n5].map(&:id), arranged.map(&:id)
end
end
+
+ def test_clone_with_modifications!
+ AncestryTestDatabase.with_model :extra_columns => {:source_id => :integer, :project_id => :integer} do |model|
+ n1 = model.create!(:project_id => nil)
+ n2 = model.create!(:parent => n1, :project_id => nil)
+ n3 = model.create!(:parent => n2, :project_id => nil)
+ n4 = model.create!(:parent => n2, :project_id => nil)
+ n5 = model.create!(:parent => n1, :project_id => nil)
+
+ n1c = n1.clone_with_modifications!({:project_id => 1}, nil, :source_id)
+
+ assert_equal n1.id, n1c.source_id
+ assert_equal 1, n1c.project_id
+ assert_equal n1.descendants.count, n1c.descendants.count
+ assert_equal 1, n1c.descendants.last.project_id
+ assert_equal n1.descendants.last.id, n1c.descendants.last.source_id
+ end
+ end
end

0 comments on commit 5027924

Please sign in to comment.