Kurt StephensNerd Up! | ||
How to duplicate DataMapper objectsKurt on Sun, 2008-11-16 21:04.
How to create a deep clone of a DataMapper::Resource object so it can be stored in a different repository. This does not work:
obj = Foo.first
obj = obj.dup
repository(:other) { obj.save }
Define DataMapper::Duplicate:
module DataMapper
module Duplicate
def duplicate_inner dup_map, opts = nil
# Recursion lock.
return obj if obj = dup_map[self.object_id]
props = { }
# Get all non-key properties.
self.class.properties(repository.name).each do | property |
next if property.key?
props[property.name] = send(property.name)
end
# Remove properties that might be FKs.
self.class.many_to_one_relationships.each do | relationship |
relationship.child_key.each do | property |
props.delete(property.name)
end
end
# Merge in any overrides.
props = props.merge opts if opts
# Create a new object.
obj = self.class.new(props)
# Prevent recursion.
dup_map[self.object_id] = obj
# Give objects a chance to deepen themselves.
obj.duplicate_deepen(dup_map)
# Deepen child relationships.
self.class.relationships.each do | (name, relationship) |
parent_model = relationship.instance_variable_get(:@parent_model)
next unless parent_model == self.class || parent_model == self.class.name
# Get current value.
name = relationship.name
value = send(name)
# Handle proxies.
case value
when DataMapper::Associations::OneToMany::Proxy,
DataMapper::Associations::ManyToMany::Proxy,
Enumerable
obj_assoc = obj.send(name)
value.each do | value |
value = value.duplicate_inner(dup_map) if value.respond_to?(:duplicate_inner)
obj_assoc << value
end
else
value = value.duplicate_inner(dup_map) if value.respond_to?(:duplicate_inner)
obj.send("#{name}=", value)
end
end
obj
end
def duplicate opts = nil
duplicate_inner({ }, opts)
end
def duplicate_deepen dup_map
self
end
end
module Resource
include Duplicate
end
end
With DataMapper::Duplicate
obj = Foo.first
obj = obj.duplicate
repository(:other) { obj.save }
Whee! |
||
Recent comments
1 day 5 hours ago
2 days 17 hours ago
3 days 12 hours ago
4 days 2 hours ago
5 days 16 hours ago
5 days 19 hours ago
1 week 20 hours ago
1 week 1 day ago
1 week 2 days ago
3 weeks 1 day ago