Reputation: 1031
Is there a way to copy the associations of one model to another...
template_model = MyModel.find(id)
new_model = template_model.clone
new_model.children << template_model.children # I want to *copy* children
...such that I copy the children from the template to the new model? (In fact this code moves children from the template to the new model).
I know I can do it manually be looping, but is there are more succinct way?
Thanks
Upvotes: 20
Views: 8066
Reputation: 7366
#dup
should be used instead of #clone
, since attributes are not copied in case of the latter.
module Promotion
class Banner
has_many :localizations
has_many :images
def deep_dup!
duplicate = dup
duplicate.save
duplicate.localizations = localizations.collect { |localization| localization.dup }
duplicate.images = images.collect { |image| image.dup }
duplicate
end
end
end
http://api.rubyonrails.org/classes/ActiveRecord/Core.html#method-i-clone http://api.rubyonrails.org/classes/ActiveRecord/Core.html#method-i-dup
Upvotes: 2
Reputation: 1861
Add this some where is under /lib. For example clone_deep.rb.
module CloneDeep
def clone_deep
kopy = clone
self.class.reflect_on_all_associations.each do |association|
next if association.macro == :belongs_to
cloned_object = case association.macro
when :has_many
self.send(association.name).collect { |item| item.clone_deep }
when :has_one
self.send(association.name) && self.send(association.name).clone_deep
else
clone
end
kopy.send("#{association.name}=", cloned_object)
end
return kopy
end
end
Create new initializer under config/initializers/ folder. Inside this file paste
ActiveRecord::Base.send(:include, CloneDeep)
Now you be able to clone model with all it's has_one and hos_many associations.
cloned_person = person.clone_deep
cloned_person.save
Upvotes: 6
Reputation: 11220
Well, it's not really a copy.
But you could do
new_model.child_ids = template_model.child_ids
Upvotes: 0
Reputation: 21950
The problem is that you are cloning the template, but not cloning it's children. Try something like:
template_model = MyModel.find(id)
new_model = template_model.clone
new_model.children << template_model.children.collect { |child| child.clone }
Upvotes: 30