-
Notifications
You must be signed in to change notification settings - Fork 0
/
clone.rb
75 lines (61 loc) · 2 KB
/
clone.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
require 'active_support'
require 'active_record'
module ActiveRecord
# == Active Model Clone
#
# Handles a simple task of cloning all attributes of a AR object
# Default behaviour is to not clone the foreign_keys.
#
# Possible options is:
# :only => [] # only clone these attributes
# :exclude => [] # Exlude these attributes, default is :id
# :skip_relations => true|false #default is true
#
# Can be configured either on a model layer using
#
# class MyModel < ActiveRecord::Base
# can_clone
# end
#
# Or can be configured upon the call to clone_ar.
module Clone
extend ActiveSupport::Concern
module ClassMethods
@options = {}
def can_clone(options={})
@options = default_options.merge(options)
end
private
# :nodoc
def foreing_keys
self.reflect_on_all_associations.map { |assoc| assoc.association_foreign_key }
end
# :nodoc
def default_options
{
:skip_relations => true,
:excluded => [:id]
}
end
end
module InstanceMethods
def clone_ar(options={})
options = (self.instance_variable_get(:@options) ? self.instance_variable_get(:@options) : self.class.send(:default_options)).merge(options)
attrs = []
if options[:only] and options[:only].is_a? Array
attrs = self.attribute_names.reject {|item| options[:only].include? item}
else
excluded = options[:excluded] + (options[:skip_relations] ? self.class.send(:foreing_keys) : [])
attrs = self.attribute_names.reject { |item| excluded.include? item}
end
newObj = self.class.new
attrs.each do |attribute|
newObj.send(:write_attribute, attribute.to_sym, self.read_attribute(attribute.to_sym))
end
yield newObj, self if block_given?
return newObj
end
end
end
end
::ActiveRecord::Base.send :include, ActiveRecord::Clone