mongo_mapper 0.8.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/UPGRADES +10 -0
- data/bin/mmconsole +0 -1
- data/examples/identity_map/automatic.rb +1 -7
- data/examples/plugins.rb +9 -9
- data/examples/safe.rb +43 -0
- data/lib/mongo_mapper.rb +46 -33
- data/lib/mongo_mapper/document.rb +33 -32
- data/lib/mongo_mapper/embedded_document.rb +22 -22
- data/lib/mongo_mapper/locale/en.yml +5 -0
- data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
- data/lib/mongo_mapper/plugins.rb +16 -3
- data/lib/mongo_mapper/plugins/accessible.rb +2 -0
- data/lib/mongo_mapper/plugins/active_model.rb +18 -0
- data/lib/mongo_mapper/plugins/associations.rb +37 -42
- data/lib/mongo_mapper/plugins/associations/base.rb +14 -50
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +58 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +6 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +30 -2
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +12 -6
- data/lib/mongo_mapper/plugins/associations/many_association.rb +67 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +5 -5
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/one_association.rb +20 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +5 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
- data/lib/mongo_mapper/plugins/associations/proxy.rb +2 -2
- data/lib/mongo_mapper/plugins/caching.rb +3 -1
- data/lib/mongo_mapper/plugins/callbacks.rb +12 -221
- data/lib/mongo_mapper/plugins/clone.rb +3 -1
- data/lib/mongo_mapper/plugins/dirty.rb +38 -91
- data/lib/mongo_mapper/plugins/document.rb +4 -2
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +2 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +43 -0
- data/lib/mongo_mapper/plugins/embedded_document.rb +16 -9
- data/lib/mongo_mapper/plugins/equality.rb +2 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +4 -2
- data/lib/mongo_mapper/plugins/indexes.rb +2 -0
- data/lib/mongo_mapper/plugins/inspect.rb +3 -1
- data/lib/mongo_mapper/plugins/keys.rb +28 -22
- data/lib/mongo_mapper/plugins/keys/key.rb +12 -6
- data/lib/mongo_mapper/plugins/logger.rb +2 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +3 -1
- data/lib/mongo_mapper/plugins/pagination.rb +2 -0
- data/lib/mongo_mapper/plugins/persistence.rb +2 -0
- data/lib/mongo_mapper/plugins/protected.rb +2 -0
- data/lib/mongo_mapper/plugins/querying.rb +5 -4
- data/lib/mongo_mapper/plugins/rails.rb +3 -5
- data/lib/mongo_mapper/plugins/safe.rb +2 -0
- data/lib/mongo_mapper/plugins/sci.rb +2 -0
- data/lib/mongo_mapper/plugins/scopes.rb +2 -0
- data/lib/mongo_mapper/plugins/serialization.rb +67 -46
- data/lib/mongo_mapper/plugins/timestamps.rb +3 -1
- data/lib/mongo_mapper/plugins/userstamps.rb +2 -0
- data/lib/mongo_mapper/plugins/validations.rb +40 -24
- data/lib/mongo_mapper/railtie.rb +49 -0
- data/lib/mongo_mapper/railtie/database.rake +60 -0
- data/lib/mongo_mapper/support/descendant_appends.rb +11 -11
- data/lib/mongo_mapper/translation.rb +10 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
- data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
- data/lib/rails/generators/mongo_mapper/model/templates/model.rb +11 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +131 -1
- data/test/functional/associations/test_in_array_proxy.rb +30 -0
- data/test/functional/associations/test_many_documents_proxy.rb +30 -2
- data/test/functional/associations/test_many_embedded_proxy.rb +33 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_one_embedded_proxy.rb +21 -2
- data/test/functional/associations/test_one_proxy.rb +49 -9
- data/test/functional/test_associations.rb +2 -0
- data/test/functional/test_caching.rb +3 -2
- data/test/functional/test_callbacks.rb +25 -18
- data/test/functional/test_dirty.rb +123 -1
- data/test/functional/test_document.rb +26 -2
- data/test/functional/test_embedded_document.rb +68 -2
- data/test/functional/test_identity_map.rb +3 -4
- data/test/functional/test_querying.rb +11 -0
- data/test/functional/test_userstamps.rb +2 -2
- data/test/functional/test_validations.rb +31 -29
- data/test/models.rb +10 -0
- data/test/test_active_model_lint.rb +1 -1
- data/test/test_helper.rb +9 -10
- data/test/unit/associations/test_base.rb +24 -100
- data/test/unit/associations/test_belongs_to_association.rb +29 -0
- data/test/unit/associations/test_many_association.rb +63 -0
- data/test/unit/associations/test_one_association.rb +18 -0
- data/test/unit/serializers/test_json_serializer.rb +0 -1
- data/test/unit/test_descendant_appends.rb +8 -16
- data/test/unit/test_document.rb +4 -9
- data/test/unit/test_dynamic_finder.rb +1 -1
- data/test/unit/test_embedded_document.rb +51 -18
- data/test/unit/test_identity_map_middleware.rb +34 -0
- data/test/unit/test_inspect.rb +22 -0
- data/test/unit/test_key.rb +21 -1
- data/test/unit/test_keys.rb +0 -2
- data/test/unit/test_plugins.rb +106 -20
- data/test/unit/test_rails.rb +8 -8
- data/test/unit/test_serialization.rb +116 -1
- data/test/unit/test_translation.rb +27 -0
- data/test/unit/test_validations.rb +66 -81
- metadata +103 -43
- data/examples/identity_map/middleware.rb +0 -14
- data/lib/mongo_mapper/plugins/descendants.rb +0 -17
- data/rails/init.rb +0 -19
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module Associations
|
5
|
+
class OneAssociation < BelongsToAssociation
|
6
|
+
def embeddable?
|
7
|
+
klass.embeddable?
|
8
|
+
end
|
9
|
+
|
10
|
+
def proxy_class
|
11
|
+
@proxy_class ||= klass.embeddable? ? OneEmbeddedProxy : OneProxy
|
12
|
+
end
|
13
|
+
|
14
|
+
def autosave?
|
15
|
+
options.fetch(:autosave, embeddable?)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -16,11 +16,16 @@ module MongoMapper
|
|
16
16
|
else
|
17
17
|
@target = klass.load(doc)
|
18
18
|
end
|
19
|
+
@target.default_id_value if @target && @target.id.nil?
|
19
20
|
assign_references(@target)
|
20
21
|
loaded
|
21
22
|
@target
|
22
23
|
end
|
23
24
|
|
25
|
+
def save_to_collection(options={})
|
26
|
+
@target.persist(options) if @target
|
27
|
+
end
|
28
|
+
|
24
29
|
protected
|
25
30
|
|
26
31
|
def find_target
|
@@ -19,7 +19,7 @@ module MongoMapper
|
|
19
19
|
load_target
|
20
20
|
|
21
21
|
if !target.nil? && target != doc
|
22
|
-
if options[:dependent] &&
|
22
|
+
if options[:dependent] && target.persisted?
|
23
23
|
case options[:dependent]
|
24
24
|
when :delete
|
25
25
|
target.delete
|
@@ -32,13 +32,13 @@ module MongoMapper
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
proxy_owner.save
|
39
|
-
doc = klass.new(doc) unless klass
|
35
|
+
if doc.nil?
|
36
|
+
target.update_attributes(foreign_key => nil) unless target.nil?
|
37
|
+
else
|
38
|
+
proxy_owner.save unless proxy_owner.persisted?
|
39
|
+
doc = klass.new(doc) unless doc.is_a?(klass)
|
40
40
|
doc[foreign_key] = proxy_owner.id
|
41
|
-
doc.save
|
41
|
+
doc.save unless doc.persisted?
|
42
42
|
loaded
|
43
43
|
@target = doc
|
44
44
|
end
|
@@ -9,7 +9,7 @@ module MongoMapper
|
|
9
9
|
alias :proxy_respond_to? :respond_to?
|
10
10
|
alias :proxy_extend :extend
|
11
11
|
|
12
|
-
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
|
12
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^respond_to_missing\?$|^object_id$)/ }
|
13
13
|
|
14
14
|
attr_reader :proxy_owner, :association, :target
|
15
15
|
|
@@ -113,7 +113,7 @@ module MongoMapper
|
|
113
113
|
def load_target
|
114
114
|
unless loaded?
|
115
115
|
if @target.is_a?(Array) && @target.any?
|
116
|
-
@target = find_target + @target.find_all { |record| record.
|
116
|
+
@target = find_target + @target.find_all { |record| !record.persisted? }
|
117
117
|
else
|
118
118
|
@target = find_target
|
119
119
|
end
|
@@ -2,10 +2,12 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Caching
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
5
7
|
module InstanceMethods
|
6
8
|
def cache_key(*suffixes)
|
7
9
|
cache_key = case
|
8
|
-
when
|
10
|
+
when !persisted?
|
9
11
|
"#{self.class.name}/new"
|
10
12
|
when timestamp = self[:updated_at]
|
11
13
|
"#{self.class.name}/#{id}-#{timestamp.to_s(:number)}"
|
@@ -1,240 +1,31 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
# Almost all of this callback stuff is pulled directly from ActiveSupport
|
3
|
-
# in the interest of support rails 2 and 3 at the same time and is the
|
4
|
-
# same copyright as rails.
|
5
2
|
module MongoMapper
|
6
3
|
module Plugins
|
7
4
|
module Callbacks
|
8
|
-
|
9
|
-
model.class_eval do
|
10
|
-
define_callbacks(
|
11
|
-
:before_save, :after_save,
|
12
|
-
:before_create, :after_create,
|
13
|
-
:before_update, :after_update,
|
14
|
-
:before_validation, :after_validation,
|
15
|
-
:before_validation_on_create, :after_validation_on_create,
|
16
|
-
:before_validation_on_update, :after_validation_on_update,
|
17
|
-
:before_destroy, :after_destroy,
|
18
|
-
:validate_on_create, :validate_on_update,
|
19
|
-
:validate
|
20
|
-
)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module ClassMethods
|
25
|
-
def define_callbacks(*callbacks)
|
26
|
-
callbacks.each do |callback|
|
27
|
-
class_eval <<-"end_eval"
|
28
|
-
def self.#{callback}(*methods, &block)
|
29
|
-
callbacks = CallbackChain.build(:#{callback}, *methods, &block)
|
30
|
-
@#{callback}_callbacks ||= CallbackChain.new
|
31
|
-
@#{callback}_callbacks.concat callbacks
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.#{callback}_callback_chain
|
35
|
-
@#{callback}_callbacks ||= CallbackChain.new
|
36
|
-
|
37
|
-
if superclass.respond_to?(:#{callback}_callback_chain)
|
38
|
-
CallbackChain.new(
|
39
|
-
superclass.#{callback}_callback_chain +
|
40
|
-
@#{callback}_callbacks
|
41
|
-
)
|
42
|
-
else
|
43
|
-
@#{callback}_callbacks
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end_eval
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
5
|
+
extend ActiveSupport::Concern
|
50
6
|
|
51
7
|
module InstanceMethods
|
52
|
-
def valid?
|
53
|
-
|
54
|
-
|
55
|
-
run_callbacks("before_validation_on_#{action}".to_sym)
|
56
|
-
result = super
|
57
|
-
run_callbacks("after_validation_on_#{action}".to_sym)
|
58
|
-
run_callbacks(:after_validation)
|
59
|
-
result
|
60
|
-
end
|
61
|
-
|
62
|
-
# Overriding validatable's valid_for_group? to integrate validation callbacks
|
63
|
-
def valid_for_group?(group) #:nodoc:
|
64
|
-
errors.clear
|
65
|
-
run_before_validations
|
66
|
-
run_callbacks(:validate)
|
67
|
-
new? ? run_callbacks(:validate_on_create) : run_callbacks(:validate_on_update)
|
68
|
-
self.class.validate_children(self, group)
|
69
|
-
self.validate_group(group)
|
70
|
-
errors.empty?
|
8
|
+
def valid?(context = nil)
|
9
|
+
context ||= (new_record? ? :create : :update)
|
10
|
+
super(context) && errors.empty?
|
71
11
|
end
|
72
12
|
|
73
13
|
def destroy
|
74
|
-
run_callbacks(:
|
75
|
-
result = super
|
76
|
-
run_callbacks(:after_destroy)
|
77
|
-
result
|
78
|
-
end
|
79
|
-
|
80
|
-
def run_callbacks(kind, options={}, &block)
|
81
|
-
callback_chain_method = "#{kind}_callback_chain"
|
82
|
-
return unless self.class.respond_to?(callback_chain_method)
|
83
|
-
self.class.send(callback_chain_method).run(self, options, &block)
|
84
|
-
self.embedded_associations.each do |association|
|
85
|
-
if association.one?
|
86
|
-
self.send(association.name).run_callbacks(kind, options, &block)
|
87
|
-
else
|
88
|
-
self.send(association.name).each do |document|
|
89
|
-
document.run_callbacks(kind, options, &block)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
def create_or_update(*args)
|
97
|
-
run_callbacks(:before_save)
|
98
|
-
if result = super
|
99
|
-
run_callbacks(:after_save)
|
100
|
-
end
|
101
|
-
result
|
102
|
-
end
|
103
|
-
|
104
|
-
def create(*args)
|
105
|
-
run_callbacks(:before_create)
|
106
|
-
result = super
|
107
|
-
run_callbacks(:after_create)
|
108
|
-
result
|
109
|
-
end
|
110
|
-
|
111
|
-
def update(*args)
|
112
|
-
run_callbacks(:before_update)
|
113
|
-
result = super
|
114
|
-
run_callbacks(:after_update)
|
115
|
-
result
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
class CallbackChain < Array
|
120
|
-
def self.build(kind, *methods, &block)
|
121
|
-
methods, options = extract_options(*methods, &block)
|
122
|
-
methods.map! { |method| Callback.new(kind, method, options) }
|
123
|
-
new(methods)
|
124
|
-
end
|
125
|
-
|
126
|
-
def run(object, options={}, &terminator)
|
127
|
-
enumerator = options[:enumerator] || :each
|
128
|
-
|
129
|
-
unless block_given?
|
130
|
-
send(enumerator) { |callback| callback.call(object) }
|
131
|
-
else
|
132
|
-
send(enumerator) do |callback|
|
133
|
-
result = callback.call(object)
|
134
|
-
break result if terminator.call(result, object)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# TODO: Decompose into more Array like behavior
|
140
|
-
def replace_or_append!(chain)
|
141
|
-
if index = index(chain)
|
142
|
-
self[index] = chain
|
143
|
-
else
|
144
|
-
self << chain
|
145
|
-
end
|
146
|
-
self
|
147
|
-
end
|
148
|
-
|
149
|
-
def find(callback, &block)
|
150
|
-
select { |c| c == callback && (!block_given? || yield(c)) }.first
|
14
|
+
run_callbacks(:destroy) { super }
|
151
15
|
end
|
152
16
|
|
153
|
-
|
154
|
-
|
17
|
+
private
|
18
|
+
def create_or_update(*)
|
19
|
+
run_callbacks(:save) { super }
|
155
20
|
end
|
156
21
|
|
157
|
-
|
158
|
-
|
159
|
-
methods.flatten!
|
160
|
-
options = methods.extract_options!
|
161
|
-
methods << block if block_given?
|
162
|
-
return methods, options
|
163
|
-
end
|
164
|
-
|
165
|
-
def extract_options(*methods, &block)
|
166
|
-
self.class.extract_options(*methods, &block)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
class Callback
|
171
|
-
attr_reader :kind, :method, :identifier, :options
|
172
|
-
|
173
|
-
def initialize(kind, method, options={})
|
174
|
-
@kind = kind
|
175
|
-
@method = method
|
176
|
-
@identifier = options[:identifier]
|
177
|
-
@options = options
|
22
|
+
def create(*)
|
23
|
+
run_callbacks(:create) { super }
|
178
24
|
end
|
179
25
|
|
180
|
-
def
|
181
|
-
|
182
|
-
when Callback
|
183
|
-
(self.identifier && self.identifier == other.identifier) || self.method == other.method
|
184
|
-
else
|
185
|
-
(self.identifier && self.identifier == other) || self.method == other
|
186
|
-
end
|
26
|
+
def update(*)
|
27
|
+
run_callbacks(:update) { super }
|
187
28
|
end
|
188
|
-
|
189
|
-
def eql?(other)
|
190
|
-
self == other
|
191
|
-
end
|
192
|
-
|
193
|
-
def dup
|
194
|
-
self.class.new(@kind, @method, @options.dup)
|
195
|
-
end
|
196
|
-
|
197
|
-
def hash
|
198
|
-
if @identifier
|
199
|
-
@identifier.hash
|
200
|
-
else
|
201
|
-
@method.hash
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def call(*args, &block)
|
206
|
-
evaluate_method(method, *args, &block) if should_run_callback?(*args)
|
207
|
-
rescue LocalJumpError
|
208
|
-
raise ArgumentError,
|
209
|
-
"Cannot yield from a Proc type filter. The Proc must take two " +
|
210
|
-
"arguments and execute #call on the second argument."
|
211
|
-
end
|
212
|
-
|
213
|
-
private
|
214
|
-
def evaluate_method(method, *args, &block)
|
215
|
-
case method
|
216
|
-
when Symbol
|
217
|
-
object = args.shift
|
218
|
-
object.send(method, *args, &block)
|
219
|
-
when String
|
220
|
-
eval(method, args.first.instance_eval { binding })
|
221
|
-
when Proc, Method
|
222
|
-
method.call(*args, &block)
|
223
|
-
else
|
224
|
-
if method.respond_to?(kind)
|
225
|
-
method.send(kind, *args, &block)
|
226
|
-
else
|
227
|
-
raise ArgumentError,
|
228
|
-
"Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
|
229
|
-
"a block to be invoked, or an object responding to the callback method."
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def should_run_callback?(*args)
|
235
|
-
[options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
|
236
|
-
![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
|
237
|
-
end
|
238
29
|
end
|
239
30
|
end
|
240
31
|
end
|
@@ -2,11 +2,13 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Clone
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
5
7
|
module InstanceMethods
|
6
8
|
def initialize_copy(other)
|
7
9
|
@_new = true
|
8
10
|
@_destroyed = false
|
9
|
-
default_id_value
|
11
|
+
default_id_value
|
10
12
|
associations.each do |name, association|
|
11
13
|
instance_variable_set(association.ivar, nil)
|
12
14
|
end
|
@@ -2,122 +2,69 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Dirty
|
5
|
-
|
6
|
-
def method_missing(method, *args, &block)
|
7
|
-
if method.to_s =~ /(_changed\?|_change|_will_change!|_was)$/
|
8
|
-
method_suffix = $1
|
9
|
-
key = method.to_s.gsub(method_suffix, '')
|
5
|
+
extend ActiveSupport::Concern
|
10
6
|
|
11
|
-
|
12
|
-
case method_suffix
|
13
|
-
when '_changed?'
|
14
|
-
key_changed?(key)
|
15
|
-
when '_change'
|
16
|
-
key_change(key)
|
17
|
-
when '_will_change!'
|
18
|
-
key_will_change!(key)
|
19
|
-
when '_was'
|
20
|
-
key_was(key)
|
21
|
-
end
|
22
|
-
else
|
23
|
-
super
|
24
|
-
end
|
25
|
-
else
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def changed?
|
31
|
-
!changed_keys.empty?
|
32
|
-
end
|
33
|
-
|
34
|
-
def changed
|
35
|
-
changed_keys.keys
|
36
|
-
end
|
37
|
-
|
38
|
-
def changes
|
39
|
-
changed.inject({}) { |h, key| h[key] = key_change(key); h }
|
40
|
-
end
|
7
|
+
include ::ActiveModel::Dirty
|
41
8
|
|
9
|
+
module InstanceMethods
|
42
10
|
def initialize(*)
|
43
11
|
# never register initial id assignment as a change
|
44
|
-
super.tap {
|
12
|
+
super.tap { changed_attributes.delete('_id') }
|
45
13
|
end
|
46
14
|
|
47
15
|
def initialize_from_database(*)
|
48
|
-
super.tap {
|
16
|
+
super.tap { changed_attributes.clear }
|
49
17
|
end
|
50
18
|
|
51
19
|
def save(*)
|
52
|
-
|
53
|
-
changed_keys.clear
|
54
|
-
end
|
55
|
-
status
|
20
|
+
clear_changes { super }
|
56
21
|
end
|
57
22
|
|
58
23
|
def save!(*)
|
59
|
-
|
60
|
-
changed_keys.clear
|
61
|
-
status
|
24
|
+
clear_changes { super }
|
62
25
|
end
|
63
26
|
|
64
27
|
def reload(*)
|
65
|
-
|
66
|
-
changed_keys.clear
|
67
|
-
document
|
28
|
+
super.tap { clear_changes }
|
68
29
|
end
|
69
30
|
|
70
|
-
|
71
|
-
def clone_key_value(key)
|
72
|
-
value = read_key(key)
|
73
|
-
value.duplicable? ? value.clone : value
|
74
|
-
rescue TypeError, NoMethodError
|
75
|
-
value
|
76
|
-
end
|
77
|
-
|
78
|
-
def changed_keys
|
79
|
-
@changed_keys ||= {}
|
80
|
-
end
|
81
|
-
|
82
|
-
def key_changed?(key)
|
83
|
-
changed_keys.include?(key)
|
84
|
-
end
|
85
|
-
|
86
|
-
def key_change(key)
|
87
|
-
[changed_keys[key], __send__(key)] if key_changed?(key)
|
88
|
-
end
|
89
|
-
|
90
|
-
def key_was(key)
|
91
|
-
key_changed?(key) ? changed_keys[key] : __send__(key)
|
92
|
-
end
|
31
|
+
protected
|
93
32
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
33
|
+
def attribute_method?(attr)
|
34
|
+
# This overrides ::ActiveSupport::Dirty#attribute_method? to allow attributes to be any key
|
35
|
+
# in the attributes hash ( default ) or any key defined on the model that may not yet have
|
36
|
+
# had a value stored in the attributes collection.
|
37
|
+
super || key_names.include?(attr)
|
38
|
+
end
|
100
39
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
40
|
+
def clear_changes
|
41
|
+
previous = changes
|
42
|
+
(block_given? ? yield : true).tap do |result|
|
43
|
+
unless result == false #failed validation; nil is OK.
|
44
|
+
@previously_changed = previous
|
45
|
+
changed_attributes.clear
|
107
46
|
end
|
108
|
-
|
109
|
-
super(key, value)
|
110
47
|
end
|
48
|
+
end
|
111
49
|
|
112
|
-
|
113
|
-
key = keys[key_name]
|
50
|
+
private
|
114
51
|
|
115
|
-
|
116
|
-
|
117
|
-
|
52
|
+
def write_key(key, value)
|
53
|
+
key = key.to_s
|
54
|
+
old = read_key(key)
|
55
|
+
attribute_will_change!(key) if attribute_should_change?(key, old, value)
|
56
|
+
changed_attributes.delete(key) unless value_changed?(key, attribute_was(key), value)
|
57
|
+
super(key, value)
|
58
|
+
end
|
118
59
|
|
119
|
-
|
120
|
-
|
60
|
+
def attribute_should_change?(key, old, value)
|
61
|
+
attribute_changed?(key) == false && value_changed?(key, old, value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def value_changed?(key_name, old, value)
|
65
|
+
value = nil if keys[key_name.to_s].number? && value.blank?
|
66
|
+
old != value
|
67
|
+
end
|
121
68
|
end
|
122
69
|
end
|
123
70
|
end
|