[Awesome Ruby Gem] Use deep_cloneable gem to clone active_record objects including associations and several operations
deep_cloneable
deep_cloneable gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations
Installation
You can install it as a gem:
1 | gem install deep_cloneable |
or add it into a Gemfile (Bundler):
1 | # Gemfile |
Usages
The deep_clone method supports a couple options that can be specified by passing an options hash. Without options, the behaviour is the same as ActiveRecord’s dup method.
Association inclusion
Associations to be included in the dup can be specified with the include option:
1 | # Single include |
The Dictionary (Object Reusage)
The dictionary ensures that models are not duped multiple times when it is associated to nested models. It does this by storing a mapping of the original object to its duped object. It can be used as follows:
1 | # Enables the dictionary (empty on initialization) |
Attribute Exceptions & Inclusions
The deep_clone method supports both except and only for specifying which attributes should be duped:
Exceptions
1 | # Single exception |
Inclusions
1 | # Single attribute inclusion |
Pre- and postprocessor
You can specify a pre- and/or a postprocessor to modify a duped object after duplication:
1 | pirate.deep_clone(include: :parrot, preprocessor: ->(original, kopy) { kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id) }) |
Note: Specifying a postprocessor is essentially the same as specifying an optional block (see below).
Note: Using deep_clone with a processors will pass all associated objects that are being cloned to the processor, so be sure to check whether the object actually responds to your method of choice.
Optional Block
Pass a block to deep_clone
to modify a duped object after duplication:
1 | pirate.deep_clone include: :parrot do |original, kopy| |
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 models with files
Carrierwave
If you are cloning models that have associated files through Carrierwave
these will not get transferred automatically. To overcome the issue you need to explicitly set the file attribute.
Easiest solution is to add the code in a clone block as described above.
1 | pirate.deep_clone include: :parrot do |original, kopy| |
ActiveStorage
For ActiveStorage, you have two options: you can either make a full copy, or share data blobs between two records.
Full copy example
1 | # Rails 5.2, has_one_attached example 1 |
Shallow copy example
1 | pirate.deep_clone include: :parrot do |original, kopy| |
Skipping missing associations
By default, deep_cloneable will throw a DeepCloneable::AssociationNotFoundException
error when an association cannot be found. You can also skip missing associations by specifying skip_missing_associations
if needed, for example when you have associations on some (but not all) subclasses of an STI model:
1 | pirate.deep_clone include: [:parrot, :rum], skip_missing_associations: true |
References
[2] deep_cloneable | RubyGems.org | your community gem host - https://rubygems.org/gems/deep_cloneable/
[4] GitHub - clowne-rb/clowne: A flexible gem for cloning models - https://github.com/clowne-rb/clowne