Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #7352: activeresource_clone_patch.diff

File activeresource_clone_patch.diff, 3.3 kB (added by rwdaigle, 1 year ago)

add ActiveResource::Base.clone

  • test/base_test.rb

    old new  
    230230    assert_raises(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') } 
    231231  end 
    232232 
     233  def test_clone 
     234    matz = Person.find(1) 
     235    matz_c = matz.clone 
     236    assert matz_c.new? 
     237    matz.attributes.each do |k, v| 
     238      assert_equal v, matz_c.send(k) if k != Person.primary_key 
     239    end 
     240  end 
     241 
     242  def test_nested_clone 
     243    addy = StreetAddress.find(1, :person_id => 1) 
     244    addy_c = addy.clone 
     245    assert addy_c.new? 
     246    addy.attributes.each do |k, v| 
     247      assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key 
     248    end 
     249    assert_equal addy.prefix_options, addy_c.prefix_options 
     250  end 
     251 
     252  def test_complex_clone 
     253    matz = Person.find(1) 
     254    matz.address = StreetAddress.find(1, :person_id => matz.id) 
     255    matz.non_ar_hash = {:not => "an ARes instance"} 
     256    matz.non_ar_arr = ["not", "ARes"] 
     257    matz_c = matz.clone 
     258    assert matz_c.new? 
     259    assert_raises(NoMethodError) {matz_c.address} 
     260    assert_equal matz.non_ar_hash, matz_c.non_ar_hash 
     261    assert_equal matz.non_ar_arr, matz_c.non_ar_arr 
     262     
     263    # Test that actual copy, not just reference copy 
     264    matz.non_ar_hash[:not] = "changed" 
     265    assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash 
     266  end 
     267 
    233268  def test_update 
    234269    matz = Person.find(:first) 
    235270    matz.name = "David" 
  • lib/active_resource/base.rb

    old new  
    165165      @prefix_options = prefix_options 
    166166    end 
    167167 
     168    # Returns a clone of the resource that hasn't been assigned an id yet and 
     169    # is treated as a new resource. 
     170    # 
     171    #  ryan = Person.find(1) 
     172    #  not_ryan = ryan.clone 
     173    #  not_ryan.new?  # => true 
     174    # 
     175    # Any active resource member attributes will NOT be cloned, though all other 
     176    # attributes are.  This is to prevent the conflict between any prefix_options 
     177    # that refer to the original parent resource and the newly cloned parent 
     178    # resource that does not exist. 
     179    # 
     180    #  ryan = Person.find(1) 
     181    #  ryan.address = StreetAddress.find(1, :person_id => ryan.id) 
     182    #  ryan.hash = {:not => "an ARes instance"} 
     183    # 
     184    #  not_ryan = ryan.clone 
     185    #  not_ryan.new?            # => true 
     186    #  not_ryan.address         # => NoMethodError 
     187    #  not_ryan.hash            # => {:not => "an ARes instance"} 
     188    # 
     189    def clone 
     190       
     191      # Clone all attributes except the pk and any nested ARes 
     192      attrs = self.attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)| 
     193        attrs[k] = v.clone 
     194        attrs 
     195      end 
     196       
     197      # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which 
     198      # attempts to convert hashes into member objects and arrays into collections of objects.  We want 
     199      # the raw objects to be cloned so we bypass load by directly setting the attributes hash. 
     200      resource = self.class.new({}, self.prefix_options) 
     201      resource.send :instance_variable_set, '@attributes', attrs 
     202      resource 
     203    end 
     204 
    168205    # Is the resource a new object? 
    169206    def new? 
    170207      id.nil?