mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add #clone. Closes #7352 [Ryan Daigle, thechrisoshow]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9121 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
5c0656c9ee
commit
ad8df03f9c
2 changed files with 72 additions and 0 deletions
|
@ -606,6 +606,43 @@ module ActiveResource
|
|||
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
|
||||
|
|
|
@ -558,6 +558,41 @@ class BaseTest < Test::Unit::TestCase
|
|||
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"
|
||||
|
|
Loading…
Reference in a new issue