Deep_cloneable
<img src=“https://travis-ci.org/moiristo/deep_cloneable.png?branch=master” alt=“Build Status” />
This gem gives every ActiveRecord::Base object the possibility to do a deep clone. It is a rails3 upgrade of the deep_cloning plugin (github.com/openminds/deep_cloning).
Requirements
-
Ruby 1.8.7, 1.9.2, 1.9.3, 2.0.0, 2.1.5 (tested)
-
Activerecord 3.1, 3.2, 4.0, 4.1, 4.2
-
Rails 2.x/3.0 users, please check out the ‘rails2.x-3.0’ branch.
Installation
-
In your Gemfile:
gem ‘deep_cloneable’, ‘~> 2.1.0’
Upgrading from v1
The ‘dup’ method with arguments has been replaced in deep_cloneable 2 by the method ‘deep_clone’. Please update your sources accordingly.
Example
Cloning one single association
pirate.deep_clone :include => :mateys
Cloning multiple associations
pirate.deep_clone :include => [:mateys, :treasures]
Cloning really deep
pirate.deep_clone :include => {:treasures => :gold_pieces}
Cloning really deep with multiple associations
pirate.deep_clone :include => [:mateys, {:treasures => :gold_pieces}]
Cloning really deep with multiple associations and a dictionary
A dictionary ensures that models are not cloned multiple times when it is associated to nested models. When using a dictionary, ensure recurring associations are cloned first:
pirate.deep_clone :include => [:mateys, {:treasures => [:matey, :gold_pieces]}], :use_dictionary => true
If this is not an option for you, it is also possible to populate the dictionary manually in advance:
dict = { :mateys => {} }
pirate.mateys.each{|m| dict[:mateys][m] = m.deep_clone }
pirate.deep_clone :include => [:mateys, {:treasures => [:matey, :gold_pieces]}], :dictionary => dict
When an object isn’t found in the dictionary, it will be populated. By passing in an empty dictionary you can populate it automatically and reuse it in subsequent deep_clones to avoid creating multiples of the same object where you have overlapping associations.
Cloning a model without an attribute
pirate.deep_clone :except => :name
Cloning a model without multiple attributes
pirate.deep_clone :except => [:name, :nick_name]
Cloning a model without an attribute or nested multiple attributes
pirate.deep_clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
Cloning with a block
pirate.deep_clone :include => :parrot do |original, kopy|
kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id)
end
Note: Using deep_clone with a block will also pass the associated objects that are being cloned to the block, so be sure to check whether the object actually responds to your method of choice.
Cloning without validations
pirate.deep_clone :include => {:treasures => :gold_pieces}, :validate => false
Cloning a model with only explicitly assigned attribute
pirate.deep_clone :only => :name
Cloning a model with only multiple explicitly assigned attributes
pirate.deep_clone :only => [:name, :nick_name]
Cloning a model with explicitly assigned attributes or nested multiple attributes
pirate.deep_clone :include => :parrot, :only => [:name, { :parrot => [:name] }]
Conditional cloning
pirate.deep_clone(:include => [{:treasures => { :gold_pieces => { :if => lambda{|piece| piece.is_a?(Parrot) } } } }, :mateys => { :unless => lambda{|matey| matey.is_a?(GoldPiece) } } ])
Note on Patches/Pull Requests
-
Fork the project.
-
Make your feature addition or bug fix.
-
Add tests for it. This is important so I don’t break it in a future version unintentionally.
-
Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
-
Send me a pull request. Bonus points for topic branches.
Copyright
Copyright © 2015 Reinier de Lange. See LICENSE for details.