Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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 jeremy authored
View
37 activeresource/lib/active_resource/base.rb
@@ -606,6 +606,43 @@ def initialize(attributes = {})
load(attributes)
end
+ # Returns a clone of the resource that hasn't been assigned an id yet and
+ # is treated as a new resource.
+ #
+ # ryan = Person.find(1)
+ # not_ryan = ryan.clone
+ # not_ryan.new? # => true
+ #
+ # Any active resource member attributes will NOT be cloned, though all other
+ # attributes are. This is to prevent the conflict between any prefix_options
+ # that refer to the original parent resource and the newly cloned parent
+ # resource that does not exist.
+ #
+ # ryan = Person.find(1)
+ # ryan.address = StreetAddress.find(1, :person_id => ryan.id)
+ # ryan.hash = {:not => "an ARes instance"}
+ #
+ # not_ryan = ryan.clone
+ # not_ryan.new? # => true
+ # not_ryan.address # => NoMethodError
+ # not_ryan.hash # => {:not => "an ARes instance"}
+ #
+ def clone
+ # Clone all attributes except the pk and any nested ARes
+ attrs = self.attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)|
+ attrs[k] = v.clone
+ attrs
+ end
+ # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
+ # attempts to convert hashes into member objects and arrays into collections of objects. We want
+ # the raw objects to be cloned so we bypass load by directly setting the attributes hash.
+ resource = self.class.new({})
+ resource.prefix_options = self.prefix_options
+ resource.send :instance_variable_set, '@attributes', attrs
+ resource
+ end
+
+
# A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).
#
# ==== Examples
View
35 activeresource/test/base_test.rb
@@ -558,6 +558,41 @@ def test_create
assert_raises(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
end
+ def test_clone
+ matz = Person.find(1)
+ matz_c = matz.clone
+ assert matz_c.new?
+ matz.attributes.each do |k, v|
+ assert_equal v, matz_c.send(k) if k != Person.primary_key
+ end
+ end
+
+ def test_nested_clone
+ addy = StreetAddress.find(1, :params => {:person_id => 1})
+ addy_c = addy.clone
+ assert addy_c.new?
+ addy.attributes.each do |k, v|
+ assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key
+ end
+ assert_equal addy.prefix_options, addy_c.prefix_options
+ end
+
+ def test_complex_clone
+ matz = Person.find(1)
+ matz.address = StreetAddress.find(1, :params => {:person_id => matz.id})
+ matz.non_ar_hash = {:not => "an ARes instance"}
+ matz.non_ar_arr = ["not", "ARes"]
+ matz_c = matz.clone
+ assert matz_c.new?
+ assert_raises(NoMethodError) {matz_c.address}
+ assert_equal matz.non_ar_hash, matz_c.non_ar_hash
+ assert_equal matz.non_ar_arr, matz_c.non_ar_arr
+
+ # Test that actual copy, not just reference copy
+ matz.non_ar_hash[:not] = "changed"
+ assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash
+ end
+
def test_update
matz = Person.find(:first)
matz.name = "David"
Please sign in to comment.
Something went wrong with that request. Please try again.