Skip to content

Instantly share code, notes, and snippets.

@zapo
Last active August 29, 2015 13:58
Show Gist options
  • Save zapo/10136601 to your computer and use it in GitHub Desktop.
Save zapo/10136601 to your computer and use it in GitHub Desktop.
dupable.rb
module Concerns
module Dupable
def duplicate
# copy self with attributes only, includes belongs_to associations
duplicate = self.dup
# copy all has_many associations...
# reject through target associations, we only want to duplicate the association models
self.class.reflect_on_all_associations(:has_many).select { |a| a.through_reflection.nil? }.each do |assoc|
duplicate.send(:"#{assoc.name}=", self.send(assoc.name.to_sym).map { |item|
item = item.respond_to?(:duplicate) ? item.duplicate : item.dup
# delete foreign_key
item.send(:"#{assoc.foreign_key}=", nil)
# populate inverse assoc if present
if assoc.inverse_of.present?
item.send(:"#{assoc.inverse_of.name}=", duplicate)
end
item
})
end
# copy all has_many through target by copying collection_ids... only needed to populate throught association targets and pass some children presence validations
# rails is too dumb to inspect association models and deduce through association targets
#
self.class.reflect_on_all_associations(:has_many).select { |a| a.through_reflection.present? }.each do |assoc|
duplicate.send(:"#{assoc.name.to_s.singularize}_ids=", self.send(:"#{assoc.name.to_s.singularize.to_sym}_ids"))
end
# copy all has_one associations
self.class.reflect_on_all_associations(:has_one).each do |assoc|
item = self.send(assoc.name.to_sym)
duplicate.send(:"#{assoc.name}=", item.respond_to?(:duplicate) ? item.duplicate : item.dup) if !item.nil?
end
duplicate
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment