Skip to content
This repository
Browse code

Add #clone. Closes #7352 [Ryan Daigle, thechrisoshow]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9121 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit ad8df03f9c831d88b8a7eb80c1b7dbcf02fc1b19 1 parent 5c0656c
Jeremy Kemper authored March 28, 2008
37  activeresource/lib/active_resource/base.rb
@@ -606,6 +606,43 @@ def initialize(attributes = {})
606 606
       load(attributes)
607 607
     end
608 608
 
  609
+    # Returns a clone of the resource that hasn't been assigned an id yet and
  610
+    # is treated as a new resource.
  611
+    #
  612
+    #  ryan = Person.find(1)
  613
+    #  not_ryan = ryan.clone
  614
+    #  not_ryan.new?  # => true
  615
+    #
  616
+    # Any active resource member attributes will NOT be cloned, though all other
  617
+    # attributes are.  This is to prevent the conflict between any prefix_options
  618
+    # that refer to the original parent resource and the newly cloned parent
  619
+    # resource that does not exist.
  620
+    #
  621
+    #  ryan = Person.find(1)
  622
+    #  ryan.address = StreetAddress.find(1, :person_id => ryan.id)
  623
+    #  ryan.hash = {:not => "an ARes instance"}
  624
+    #
  625
+    #  not_ryan = ryan.clone
  626
+    #  not_ryan.new?            # => true
  627
+    #  not_ryan.address         # => NoMethodError
  628
+    #  not_ryan.hash            # => {:not => "an ARes instance"}
  629
+    #
  630
+    def clone
  631
+      # Clone all attributes except the pk and any nested ARes
  632
+      attrs = self.attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)|
  633
+        attrs[k] = v.clone
  634
+        attrs
  635
+      end
  636
+      # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
  637
+      # attempts to convert hashes into member objects and arrays into collections of objects.  We want
  638
+      # the raw objects to be cloned so we bypass load by directly setting the attributes hash.
  639
+      resource = self.class.new({})
  640
+      resource.prefix_options = self.prefix_options
  641
+      resource.send :instance_variable_set, '@attributes', attrs
  642
+      resource
  643
+    end
  644
+
  645
+
609 646
     # A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).
610 647
     #
611 648
     # ==== Examples
35  activeresource/test/base_test.rb
@@ -558,6 +558,41 @@ def test_create
558 558
     assert_raises(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
559 559
   end
560 560
 
  561
+  def test_clone
  562
+   matz = Person.find(1)
  563
+   matz_c = matz.clone
  564
+   assert matz_c.new?
  565
+   matz.attributes.each do |k, v|
  566
+     assert_equal v, matz_c.send(k) if k != Person.primary_key
  567
+   end
  568
+ end
  569
+
  570
+ def test_nested_clone
  571
+   addy = StreetAddress.find(1, :params => {:person_id => 1})
  572
+   addy_c = addy.clone
  573
+   assert addy_c.new?
  574
+   addy.attributes.each do |k, v|
  575
+     assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key
  576
+   end
  577
+   assert_equal addy.prefix_options, addy_c.prefix_options
  578
+ end
  579
+
  580
+ def test_complex_clone
  581
+   matz = Person.find(1)
  582
+   matz.address = StreetAddress.find(1, :params => {:person_id => matz.id})
  583
+   matz.non_ar_hash = {:not => "an ARes instance"}
  584
+   matz.non_ar_arr = ["not", "ARes"]
  585
+   matz_c = matz.clone
  586
+   assert matz_c.new?
  587
+   assert_raises(NoMethodError) {matz_c.address}
  588
+   assert_equal matz.non_ar_hash, matz_c.non_ar_hash
  589
+   assert_equal matz.non_ar_arr, matz_c.non_ar_arr
  590
+
  591
+   # Test that actual copy, not just reference copy
  592
+   matz.non_ar_hash[:not] = "changed"
  593
+   assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash
  594
+ end
  595
+
561 596
   def test_update
562 597
     matz = Person.find(:first)
563 598
     matz.name = "David"

0 notes on commit ad8df03

Please sign in to comment.
Something went wrong with that request. Please try again.