Module: ActiveRecord::Base::DeepCloneable
- Included in:
- ActiveRecord::Base
- Defined in:
- lib/deep_cloneable.rb
Defined Under Namespace
Classes: AssociationNotFoundException
Instance Method Summary collapse
-
#dup(*args, &block) ⇒ Object
clones an ActiveRecord model.
Instance Method Details
#dup(*args, &block) ⇒ Object
clones an ActiveRecord model. if passed the :include option, it will deep clone the given associations if passed the :except option, it won’t clone the given attributes
Usage:
Cloning one single association
pirate.clone :include => :mateys
Cloning multiple associations
pirate.clone :include => [:mateys, :treasures]
Cloning really deep
pirate.clone :include => {:treasures => :gold_pieces}
Cloning really deep with multiple associations
pirate.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.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.clone }
pirate.clone :include => [:mateys, {:treasures => [:matey, :gold_pieces], :dictionary => dict }]
Cloning a model without an attribute
pirate.clone :except => :name
Cloning a model without multiple attributes
pirate.clone :except => [:name, :nick_name]
Cloning a model without an attribute or nested multiple attributes
pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/deep_cloneable.rb', line 60 def dup *args, &block = args[0] || {} dict = [:dictionary] dict ||= {} if .delete(:use_dictionary) kopy = unless dict super() else tableized_class = self.class.name.tableize.to_sym dict[tableized_class] ||= {} dict[tableized_class][self] ||= super() end block.call(self, kopy) if block deep_exceptions = {} if [:except] exceptions = [:except].nil? ? [] : [[:except]].flatten exceptions.each do |attribute| kopy.send(:write_attribute, attribute, self.class.column_defaults.dup[attribute.to_s]) unless attribute.kind_of?(Hash) end deep_exceptions = exceptions.select{|e| e.kind_of?(Hash) }.inject({}){|m,h| m.merge(h) } end if [:include] Array([:include]).each do |association, deep_associations| if (association.kind_of? Hash) deep_associations = association[association.keys.first] association = association.keys.first end = deep_associations.blank? ? {} : {:include => deep_associations} .merge!(:except => deep_exceptions[association]) if deep_exceptions[association] .merge!(:dictionary => dict) if dict association_reflection = self.class.reflect_on_association(association) raise AssociationNotFoundException.new("#{self.class}##{association}") if association_reflection.nil? if [:validate] == false kopy.instance_eval do # Force :validate => false on all saves. def perform_validations(={}) [:validate] = false super() end end end cloned_object = send( "dup_#{association_reflection.macro}_#{association_reflection.class.name.demodulize.underscore.gsub('_reflection', '')}", { :reflection => association_reflection, :association => association, :copy => kopy, :dup_options => }, &block ) kopy.send("#{association}=", cloned_object) end end return kopy end |