mongoid 2.4.0 → 2.4.1
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/CHANGELOG.md +49 -1
- data/lib/mongoid/attributes.rb +1 -1
- data/lib/mongoid/config/environment.rb +1 -1
- data/lib/mongoid/contexts/mongo.rb +29 -11
- data/lib/mongoid/criterion/selector.rb +22 -4
- data/lib/mongoid/dirty.rb +61 -18
- data/lib/mongoid/extensions/string/inflections.rb +1 -1
- data/lib/mongoid/fields.rb +148 -24
- data/lib/mongoid/fields/internal/array.rb +13 -8
- data/lib/mongoid/fields/internal/foreign_keys/array.rb +13 -8
- data/lib/mongoid/fields/internal/set.rb +1 -1
- data/lib/mongoid/persistence/insertion.rb +2 -1
- data/lib/mongoid/persistence/operations/update.rb +0 -9
- data/lib/mongoid/relations/cascading.rb +0 -1
- data/lib/mongoid/relations/cascading/delete.rb +18 -1
- data/lib/mongoid/relations/cascading/destroy.rb +18 -1
- data/lib/mongoid/relations/cascading/nullify.rb +18 -1
- data/lib/mongoid/relations/referenced/many.rb +6 -8
- data/lib/mongoid/relations/referenced/many_to_many.rb +2 -4
- data/lib/mongoid/validations/uniqueness.rb +1 -0
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/mongoid.rb +8 -9
- metadata +21 -22
- data/lib/mongoid/relations/cascading/strategy.rb +0 -26
data/CHANGELOG.md
CHANGED
@@ -3,7 +3,55 @@
|
|
3
3
|
For instructions on upgrading to newer versions, visit
|
4
4
|
[mongoid.org](http://mongoid.org/docs/upgrading.html).
|
5
5
|
|
6
|
-
## 2.4.
|
6
|
+
## 2.4.1 \[ In Development \] \[ Branch: 2.4.0-stable \]
|
7
|
+
|
8
|
+
### Resolved Issues
|
9
|
+
|
10
|
+
* \#1593 Arrays on embedded documents now properly atomically update when
|
11
|
+
modified from original version.
|
12
|
+
|
13
|
+
* \#1592 Don't swallow exceptions from index generation in the create_indexes
|
14
|
+
rake task.
|
15
|
+
|
16
|
+
* \#1589 Allow assignment of empty array to HABTM when no documents are yet
|
17
|
+
loaded into memory.
|
18
|
+
|
19
|
+
* \#1587 When a previous value for an array field was an explicit nil, it can
|
20
|
+
now be reset atomically with new values.
|
21
|
+
|
22
|
+
* \#1585 `Model#respond_to?` returns true now for the setter when allowing
|
23
|
+
dynamic fields.
|
24
|
+
|
25
|
+
* \#1582 Allow nil values to be set in arrays.
|
26
|
+
|
27
|
+
* \#1580 Allow arrays to be set to nil post save, and not just empty.
|
28
|
+
|
29
|
+
* \#1579 Don't call #to_a on individual set field elements in criterion.
|
30
|
+
|
31
|
+
* \#1576 Don't hit database on uniqueness validation if the field getting
|
32
|
+
validated has not changed.
|
33
|
+
|
34
|
+
* \#1571 Aliased fields get all the dirty attribute methods and all getters and
|
35
|
+
setters for both the original name and the alias. (Hans Hasselberg)
|
36
|
+
|
37
|
+
* \#1568 Fallback to development environment with warning when no env configured.
|
38
|
+
|
39
|
+
* \#1565 For fields and foreign keys with non-standard Ruby or database names,
|
40
|
+
use define_method instead of class_eval for creating the accessors and
|
41
|
+
dirty methods.
|
42
|
+
|
43
|
+
* \#1557 Internal strategy class no longer conflicts with models.
|
44
|
+
|
45
|
+
* \#1551 Parent documents now return `true` for `Model#changed?` if only child
|
46
|
+
(embedded) documents have changed.
|
47
|
+
|
48
|
+
* \#1547 Resetting persisted children from a parent save when new waits until post
|
49
|
+
callbacks, mirroring update functionality.
|
50
|
+
|
51
|
+
* \#1536 Eager loading now happens when calling `first` or `last` on a
|
52
|
+
criteria if inclusions are specified.
|
53
|
+
|
54
|
+
## 2.4.0
|
7
55
|
|
8
56
|
### New Features
|
9
57
|
|
data/lib/mongoid/attributes.rb
CHANGED
@@ -19,7 +19,7 @@ module Mongoid #:nodoc
|
|
19
19
|
def env_name
|
20
20
|
return Rails.env if defined?(Rails)
|
21
21
|
return Sinatra::Base.environment.to_s if defined?(Sinatra)
|
22
|
-
ENV["RACK_ENV"] || raise(Errors::NoEnvironment.new)
|
22
|
+
ENV["RACK_ENV"] || ENV["MONGOID_ENV"] || raise(Errors::NoEnvironment.new)
|
23
23
|
end
|
24
24
|
|
25
25
|
# Load the yaml from the provided path and return the settings for the
|
@@ -135,6 +135,26 @@ module Mongoid #:nodoc:
|
|
135
135
|
klass.collection.distinct(field, selector)
|
136
136
|
end
|
137
137
|
|
138
|
+
# Eager load the inclusions for the provided documents.
|
139
|
+
#
|
140
|
+
# @example Eager load the inclusions.
|
141
|
+
# context.eager_load(docs)
|
142
|
+
#
|
143
|
+
# @param [ Array<Document> ] docs The docs returning from the db.
|
144
|
+
#
|
145
|
+
# @since 2.4.1
|
146
|
+
def eager_load(docs)
|
147
|
+
parent_ids = docs.map(&:id)
|
148
|
+
criteria.inclusions.reject! do |metadata|
|
149
|
+
if metadata.macro == :referenced_in
|
150
|
+
child_ids = load_ids(metadata.foreign_key)
|
151
|
+
metadata.eager_load(child_ids)
|
152
|
+
else
|
153
|
+
metadata.eager_load(parent_ids)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
138
158
|
# Execute the context. This will take the selector and options
|
139
159
|
# and pass them on to the Ruby driver's +find()+ method on the collection. The
|
140
160
|
# collection itself will be retrieved from the class provided, and once the
|
@@ -148,15 +168,7 @@ module Mongoid #:nodoc:
|
|
148
168
|
collection, options = klass.collection, process_options
|
149
169
|
if criteria.inclusions.any?
|
150
170
|
collection.find(selector, options).entries.tap do |docs|
|
151
|
-
|
152
|
-
criteria.inclusions.reject! do |metadata|
|
153
|
-
if metadata.macro == :referenced_in
|
154
|
-
child_ids = load_ids(metadata.foreign_key)
|
155
|
-
metadata.eager_load(child_ids)
|
156
|
-
else
|
157
|
-
metadata.eager_load(parent_ids)
|
158
|
-
end
|
159
|
-
end
|
171
|
+
eager_load(docs)
|
160
172
|
end
|
161
173
|
else
|
162
174
|
collection.find(selector, options)
|
@@ -189,7 +201,10 @@ module Mongoid #:nodoc:
|
|
189
201
|
# @return [ Document ] The first document in the collection.
|
190
202
|
def first
|
191
203
|
attributes = klass.collection.find_one(selector, options_with_default_sorting)
|
192
|
-
|
204
|
+
return nil unless attributes
|
205
|
+
Mongoid::Factory.from_db(klass, attributes).tap do |doc|
|
206
|
+
eager_load([ doc ]) if criteria.inclusions.any?
|
207
|
+
end
|
193
208
|
end
|
194
209
|
alias :one :first
|
195
210
|
|
@@ -255,7 +270,10 @@ module Mongoid #:nodoc:
|
|
255
270
|
opts = options_with_default_sorting
|
256
271
|
opts[:sort] = opts[:sort].map{ |option| [ option[0], option[1].invert ] }.uniq
|
257
272
|
attributes = klass.collection.find_one(selector, opts)
|
258
|
-
|
273
|
+
return nil unless attributes
|
274
|
+
Mongoid::Factory.from_db(klass, attributes).tap do |doc|
|
275
|
+
eager_load([ doc ]) if criteria.inclusions.any?
|
276
|
+
end
|
259
277
|
end
|
260
278
|
|
261
279
|
# Return the max value for a field.
|
@@ -85,11 +85,29 @@ module Mongoid #:nodoc:
|
|
85
85
|
# @since 1.0.0
|
86
86
|
def try_to_typecast(key, value)
|
87
87
|
access = key.to_s
|
88
|
-
if
|
89
|
-
|
88
|
+
if field = fields[key.to_s] || fields[aliased_fields[key.to_s]]
|
89
|
+
typecast_value_for(field, value)
|
90
|
+
elsif proper_and_or_value?(key, value)
|
91
|
+
handle_and_or_value(value)
|
92
|
+
else
|
93
|
+
value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def proper_and_or_value?(key, value)
|
98
|
+
["$and", "$or"].include?(key) &&
|
99
|
+
value.is_a?(Array) &&
|
100
|
+
value.all?{ |e| e.is_a?(Hash) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def handle_and_or_value(values)
|
104
|
+
[].tap do |result|
|
105
|
+
values.map do |value|
|
106
|
+
value.each do |key, value|
|
107
|
+
result.push key => try_to_typecast(key, value)
|
108
|
+
end
|
109
|
+
end
|
90
110
|
end
|
91
|
-
field = fields[access] || fields[aliased_fields[access]]
|
92
|
-
typecast_value_for(field, value)
|
93
111
|
end
|
94
112
|
|
95
113
|
# Get the typecast value for the defined field.
|
data/lib/mongoid/dirty.rb
CHANGED
@@ -24,7 +24,21 @@ module Mongoid #:nodoc:
|
|
24
24
|
#
|
25
25
|
# @since 2.4.0
|
26
26
|
def changed?
|
27
|
-
changed_attributes.any?
|
27
|
+
changed_attributes.any? || children_changed?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Have any children (embedded documents) of this document changed?
|
31
|
+
#
|
32
|
+
# @example Have any children changed?
|
33
|
+
# model.children_changed?
|
34
|
+
#
|
35
|
+
# @return [ true, false ] If any children have changed.
|
36
|
+
#
|
37
|
+
# @since 2.4.1
|
38
|
+
def children_changed?
|
39
|
+
_children.any? do |child|
|
40
|
+
child.changed?
|
41
|
+
end
|
28
42
|
end
|
29
43
|
|
30
44
|
# Get the attribute changes.
|
@@ -117,8 +131,14 @@ module Mongoid #:nodoc:
|
|
117
131
|
field = fields[name]
|
118
132
|
key = embedded? ? "#{atomic_position}.#{name}" : name
|
119
133
|
if field && field.resizable?
|
120
|
-
|
121
|
-
|
134
|
+
field.add_atomic_changes(
|
135
|
+
self,
|
136
|
+
name,
|
137
|
+
key,
|
138
|
+
modifications,
|
139
|
+
new,
|
140
|
+
old
|
141
|
+
)
|
122
142
|
else
|
123
143
|
modifications[key] = new
|
124
144
|
end
|
@@ -207,36 +227,59 @@ module Mongoid #:nodoc:
|
|
207
227
|
# Generate all the dirty methods needed for the attribute.
|
208
228
|
#
|
209
229
|
# @example Generate the dirty methods.
|
210
|
-
# Model.create_dirty_methods("name")
|
230
|
+
# Model.create_dirty_methods("name", "name")
|
211
231
|
#
|
212
|
-
# @param [ String ] name The name of the
|
232
|
+
# @param [ String ] name The name of the field.
|
233
|
+
# @param [ String ] name The name of the accessor.
|
213
234
|
#
|
214
235
|
# @return [ Module ] The fields module.
|
215
236
|
#
|
216
237
|
# @since 2.4.0
|
217
|
-
def create_dirty_methods(name)
|
238
|
+
def create_dirty_methods(name, meth)
|
218
239
|
generated_methods.module_eval do
|
219
|
-
|
220
|
-
|
221
|
-
attribute_change(
|
240
|
+
if meth =~ /\W/
|
241
|
+
define_method("#{meth}_change") do
|
242
|
+
attribute_change(name)
|
222
243
|
end
|
223
244
|
|
224
|
-
|
225
|
-
attribute_changed?(
|
245
|
+
define_method("#{meth}_changed?") do
|
246
|
+
attribute_changed?(name)
|
226
247
|
end
|
227
248
|
|
228
|
-
|
229
|
-
attribute_was(
|
249
|
+
define_method("#{meth}_was") do
|
250
|
+
attribute_was(name)
|
230
251
|
end
|
231
252
|
|
232
|
-
|
233
|
-
attribute_will_change!(
|
253
|
+
define_method("#{meth}_will_change!") do
|
254
|
+
attribute_will_change!(name)
|
234
255
|
end
|
235
256
|
|
236
|
-
|
237
|
-
reset_attribute!(
|
257
|
+
define_method("reset_#{meth}!") do
|
258
|
+
reset_attribute!(name)
|
238
259
|
end
|
239
|
-
|
260
|
+
else
|
261
|
+
class_eval <<-EOM
|
262
|
+
def #{meth}_change
|
263
|
+
attribute_change(#{name.inspect})
|
264
|
+
end
|
265
|
+
|
266
|
+
def #{meth}_changed?
|
267
|
+
attribute_changed?(#{name.inspect})
|
268
|
+
end
|
269
|
+
|
270
|
+
def #{meth}_was
|
271
|
+
attribute_was(#{name.inspect})
|
272
|
+
end
|
273
|
+
|
274
|
+
def #{meth}_will_change!
|
275
|
+
attribute_will_change!(#{name.inspect})
|
276
|
+
end
|
277
|
+
|
278
|
+
def reset_#{meth}!
|
279
|
+
reset_attribute!(#{name.inspect})
|
280
|
+
end
|
281
|
+
EOM
|
282
|
+
end
|
240
283
|
end
|
241
284
|
end
|
242
285
|
end
|
data/lib/mongoid/fields.rb
CHANGED
@@ -276,14 +276,15 @@ module Mongoid #:nodoc
|
|
276
276
|
def add_field(name, options = {})
|
277
277
|
aliased = options[:as]
|
278
278
|
aliased_fields[aliased.to_s] = name if aliased
|
279
|
-
meth = aliased || name
|
280
279
|
type = options[:localize] ? Fields::Internal::Localized : options[:type]
|
281
280
|
Mappings.for(type, options[:identity]).instantiate(name, options).tap do |field|
|
282
281
|
fields[name] = field
|
283
282
|
add_defaults(field)
|
284
|
-
create_accessors(name,
|
283
|
+
create_accessors(name, name, options)
|
284
|
+
create_accessors(name, aliased, options) if aliased
|
285
285
|
process_options(field)
|
286
|
-
create_dirty_methods(name)
|
286
|
+
create_dirty_methods(name, name)
|
287
|
+
create_dirty_methods(name, aliased) if aliased
|
287
288
|
end
|
288
289
|
end
|
289
290
|
|
@@ -337,43 +338,164 @@ module Mongoid #:nodoc
|
|
337
338
|
# @param [ Symbol ] name The name of the field.
|
338
339
|
# @param [ Symbol ] meth The name of the accessor.
|
339
340
|
# @param [ Hash ] options The options.
|
341
|
+
#
|
342
|
+
# @since 2.0.0
|
340
343
|
def create_accessors(name, meth, options = {})
|
341
344
|
field = fields[name]
|
345
|
+
|
346
|
+
create_field_getter(name, meth, field)
|
347
|
+
create_field_setter(name, meth)
|
348
|
+
create_field_check(name, meth)
|
349
|
+
|
350
|
+
if options[:localize]
|
351
|
+
create_translations_getter(name, meth)
|
352
|
+
create_translations_setter(name, meth)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# Create the getter method for the provided field.
|
357
|
+
#
|
358
|
+
# @example Create the getter.
|
359
|
+
# Model.create_field_getter("name", "name", field)
|
360
|
+
#
|
361
|
+
# @param [ String ] name The name of the attribute.
|
362
|
+
# @param [ String ] meth The name of the method.
|
363
|
+
# @param [ Field ] field The field.
|
364
|
+
#
|
365
|
+
# @since 2.4.0
|
366
|
+
def create_field_getter(name, meth, field)
|
342
367
|
generated_methods.module_eval do
|
343
|
-
if
|
344
|
-
|
345
|
-
|
346
|
-
fields[
|
368
|
+
if meth =~ /\W/
|
369
|
+
if field.cast_on_read?
|
370
|
+
define_method(meth) do
|
371
|
+
fields[name].deserialize(read_attribute(name))
|
347
372
|
end
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
def #{meth}
|
352
|
-
read_attribute(#{name.inspect}).tap do |value|
|
373
|
+
else
|
374
|
+
define_method(meth) do
|
375
|
+
read_attribute(name).tap do |value|
|
353
376
|
if value.is_a?(Array) || value.is_a?(Hash)
|
354
|
-
attribute_will_change!(
|
377
|
+
attribute_will_change!(name)
|
355
378
|
end
|
356
379
|
end
|
357
380
|
end
|
358
|
-
|
381
|
+
end
|
382
|
+
else
|
383
|
+
if field.cast_on_read?
|
384
|
+
class_eval <<-EOM
|
385
|
+
def #{meth}
|
386
|
+
fields[#{name.inspect}].deserialize(read_attribute(#{name.inspect}))
|
387
|
+
end
|
388
|
+
EOM
|
389
|
+
else
|
390
|
+
class_eval <<-EOM
|
391
|
+
def #{meth}
|
392
|
+
read_attribute(#{name.inspect}).tap do |value|
|
393
|
+
if value.is_a?(Array) || value.is_a?(Hash)
|
394
|
+
attribute_will_change!(#{name.inspect})
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
EOM
|
399
|
+
end
|
359
400
|
end
|
360
|
-
|
361
|
-
|
362
|
-
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
# Create the setter method for the provided field.
|
405
|
+
#
|
406
|
+
# @example Create the setter.
|
407
|
+
# Model.create_field_setter("name", "name")
|
408
|
+
#
|
409
|
+
# @param [ String ] name The name of the attribute.
|
410
|
+
# @param [ String ] meth The name of the method.
|
411
|
+
#
|
412
|
+
# @since 2.4.0
|
413
|
+
def create_field_setter(name, meth)
|
414
|
+
generated_methods.module_eval do
|
415
|
+
if meth =~ /\W/
|
416
|
+
define_method(meth) do |value|
|
417
|
+
write_attribute(name, value)
|
363
418
|
end
|
419
|
+
else
|
420
|
+
class_eval <<-EOM
|
421
|
+
def #{meth}=(value)
|
422
|
+
write_attribute(#{name.inspect}, value)
|
423
|
+
end
|
424
|
+
EOM
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
364
428
|
|
365
|
-
|
366
|
-
|
429
|
+
# Create the check method for the provided field.
|
430
|
+
#
|
431
|
+
# @example Create the check.
|
432
|
+
# Model.create_field_check("name", "name")
|
433
|
+
#
|
434
|
+
# @param [ String ] name The name of the attribute.
|
435
|
+
# @param [ String ] meth The name of the method.
|
436
|
+
#
|
437
|
+
# @since 2.4.0
|
438
|
+
def create_field_check(name, meth)
|
439
|
+
generated_methods.module_eval do
|
440
|
+
if meth =~ /\W/
|
441
|
+
define_method("#{meth}?") do
|
442
|
+
attr = read_attribute(name)
|
367
443
|
attr == true || attr.present?
|
368
444
|
end
|
369
|
-
|
445
|
+
else
|
446
|
+
class_eval <<-EOM
|
447
|
+
def #{meth}?
|
448
|
+
attr = read_attribute(#{name.inspect})
|
449
|
+
attr == true || attr.present?
|
450
|
+
end
|
451
|
+
EOM
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
370
455
|
|
371
|
-
|
456
|
+
# Create the translation getter method for the provided field.
|
457
|
+
#
|
458
|
+
# @example Create the translation getter.
|
459
|
+
# Model.create_translations_getter("name", "name")
|
460
|
+
#
|
461
|
+
# @param [ String ] name The name of the attribute.
|
462
|
+
# @param [ String ] meth The name of the method.
|
463
|
+
#
|
464
|
+
# @since 2.4.0
|
465
|
+
def create_translations_getter(name, meth)
|
466
|
+
generated_methods.module_eval do
|
467
|
+
if meth =~ /\W/
|
468
|
+
define_method("#{meth}_translations") do
|
469
|
+
attributes[name]
|
470
|
+
end
|
471
|
+
else
|
372
472
|
class_eval <<-EOM
|
373
473
|
def #{meth}_translations
|
374
474
|
attributes[#{name.inspect}]
|
375
475
|
end
|
476
|
+
EOM
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
376
480
|
|
481
|
+
# Create the translation setter method for the provided field.
|
482
|
+
#
|
483
|
+
# @example Create the translation setter.
|
484
|
+
# Model.create_translations_setter("name", "name")
|
485
|
+
#
|
486
|
+
# @param [ String ] name The name of the attribute.
|
487
|
+
# @param [ String ] meth The name of the method.
|
488
|
+
#
|
489
|
+
# @since 2.4.0
|
490
|
+
def create_translations_setter(name, meth)
|
491
|
+
generated_methods.module_eval do
|
492
|
+
if meth =~ /\W/
|
493
|
+
define_method("#{meth}_translations=") do |value|
|
494
|
+
attribute_will_change!(name)
|
495
|
+
attributes[name] = value
|
496
|
+
end
|
497
|
+
else
|
498
|
+
class_eval <<-EOM
|
377
499
|
def #{meth}_translations=(value)
|
378
500
|
attribute_will_change!(#{name.inspect})
|
379
501
|
attributes[#{name.inspect}] = value
|
@@ -387,11 +509,13 @@ module Mongoid #:nodoc
|
|
387
509
|
#
|
388
510
|
# @example Include the fields.
|
389
511
|
# Person.generated_methods
|
512
|
+
#
|
513
|
+
# @return [ Module ] The module of generated methods.
|
514
|
+
#
|
515
|
+
# @since 2.0.0
|
390
516
|
def generated_methods
|
391
517
|
@generated_methods ||= begin
|
392
|
-
Module.new.tap
|
393
|
-
include mod
|
394
|
-
end
|
518
|
+
Module.new.tap { |mod| include(mod) }
|
395
519
|
end
|
396
520
|
end
|
397
521
|
end
|
@@ -13,19 +13,24 @@ module Mongoid #:nodoc:
|
|
13
13
|
# field.add_atomic_changes(doc, "key", {}, [], [])
|
14
14
|
#
|
15
15
|
# @param [ Document ] document The document to add to.
|
16
|
-
# @param [ String ]
|
16
|
+
# @param [ String ] name The name of the field.
|
17
|
+
# @param [ String ] key The atomic location of the field.
|
17
18
|
# @param [ Hash ] mods The current modifications.
|
18
19
|
# @param [ Array ] new The new elements to add.
|
19
20
|
# @param [ Array ] old The old elements getting removed.
|
20
21
|
#
|
21
22
|
# @since 2.4.0
|
22
|
-
def add_atomic_changes(document, key, mods, new, old)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
elsif
|
28
|
-
|
23
|
+
def add_atomic_changes(document, name, key, mods, new, old)
|
24
|
+
pushes = (new || []) - (old || [])
|
25
|
+
pulls = (old || []) - (new || [])
|
26
|
+
if old.nil?
|
27
|
+
mods[key] = pushes
|
28
|
+
elsif !pushes.empty? && !pulls.empty?
|
29
|
+
mods[key] = document.attributes[name]
|
30
|
+
elsif !pushes.empty?
|
31
|
+
document.atomic_array_pushes[key] = pushes
|
32
|
+
elsif !pulls.empty?
|
33
|
+
document.atomic_array_pulls[key] = pulls
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
@@ -14,19 +14,24 @@ module Mongoid #:nodoc:
|
|
14
14
|
# field.add_atomic_changes(doc, "key", {}, [], [])
|
15
15
|
#
|
16
16
|
# @param [ Document ] document The document to add to.
|
17
|
-
# @param [ String ]
|
17
|
+
# @param [ String ] name The name of the field.
|
18
|
+
# @param [ String ] key The atomic location of the field.
|
18
19
|
# @param [ Hash ] mods The current modifications.
|
19
20
|
# @param [ Array ] new The new elements to add.
|
20
21
|
# @param [ Array ] old The old elements getting removed.
|
21
22
|
#
|
22
23
|
# @since 2.4.0
|
23
|
-
def add_atomic_changes(document, key, mods, new, old)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
elsif
|
29
|
-
|
24
|
+
def add_atomic_changes(document, name, key, mods, new, old)
|
25
|
+
pushes = (new || []) - (old || [])
|
26
|
+
pulls = (old || []) - (new || [])
|
27
|
+
if old.nil?
|
28
|
+
mods[key] = pushes
|
29
|
+
elsif !pushes.empty? && !pulls.empty?
|
30
|
+
mods[key] = document.attributes[name]
|
31
|
+
elsif !pushes.empty?
|
32
|
+
document.atomic_array_add_to_sets[key] = pushes
|
33
|
+
elsif !pulls.empty?
|
34
|
+
document.atomic_array_pulls[key] = pulls
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
@@ -25,11 +25,12 @@ module Mongoid #:nodoc:
|
|
25
25
|
doc.run_callbacks(:create) do
|
26
26
|
yield(doc)
|
27
27
|
doc.new_record = false
|
28
|
-
|
28
|
+
true
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
unless result == false
|
33
|
+
doc.reset_persisted_children
|
33
34
|
doc.move_changes
|
34
35
|
Threaded.clear_options!
|
35
36
|
end
|
@@ -42,15 +42,6 @@ module Mongoid #:nodoc:
|
|
42
42
|
def persist
|
43
43
|
prepare do
|
44
44
|
unless updates.empty?
|
45
|
-
# @todo Durran: This is a temporary fix for #791 until we rewrite
|
46
|
-
# the dirty tracking to properly flag a document as changed if
|
47
|
-
# only embedded documents have changed.
|
48
|
-
if document.respond_to?(:updated_at)
|
49
|
-
if document.timestamping? && !document.updated_at_changed?
|
50
|
-
document.updated_at = Time.now
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
45
|
collection.update(selector, updates, options)
|
55
46
|
conflicts.each_pair do |key, value|
|
56
47
|
collection.update(selector, { key => value }, options)
|
@@ -2,7 +2,24 @@
|
|
2
2
|
module Mongoid # :nodoc:
|
3
3
|
module Relations #:nodoc:
|
4
4
|
module Cascading #:nodoc:
|
5
|
-
class Delete
|
5
|
+
class Delete
|
6
|
+
|
7
|
+
attr_accessor :document, :relation, :metadata
|
8
|
+
|
9
|
+
# Initialize the new cascade strategy, which will set up the relation
|
10
|
+
# and the metadata.
|
11
|
+
#
|
12
|
+
# @example Instantiate the strategy
|
13
|
+
# Strategy.new(document, metadata)
|
14
|
+
#
|
15
|
+
# @param [ Document ] document The document to cascade from.
|
16
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
17
|
+
#
|
18
|
+
# @return [ Strategy ] The new strategy.
|
19
|
+
def initialize(document, metadata)
|
20
|
+
@document, @metadata = document, metadata
|
21
|
+
@relation = document.send(metadata.name)
|
22
|
+
end
|
6
23
|
|
7
24
|
# Execute the cascading deletion for the relation if it already exists.
|
8
25
|
# This should be optimized in the future potentially not to load all
|
@@ -2,7 +2,24 @@
|
|
2
2
|
module Mongoid # :nodoc:
|
3
3
|
module Relations #:nodoc:
|
4
4
|
module Cascading #:nodoc:
|
5
|
-
class Destroy
|
5
|
+
class Destroy
|
6
|
+
|
7
|
+
attr_accessor :document, :relation, :metadata
|
8
|
+
|
9
|
+
# Initialize the new cascade strategy, which will set up the relation
|
10
|
+
# and the metadata.
|
11
|
+
#
|
12
|
+
# @example Instantiate the strategy
|
13
|
+
# Strategy.new(document, metadata)
|
14
|
+
#
|
15
|
+
# @param [ Document ] document The document to cascade from.
|
16
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
17
|
+
#
|
18
|
+
# @return [ Strategy ] The new strategy.
|
19
|
+
def initialize(document, metadata)
|
20
|
+
@document, @metadata = document, metadata
|
21
|
+
@relation = document.send(metadata.name)
|
22
|
+
end
|
6
23
|
|
7
24
|
# Execute the cascading deletion for the relation if it already exists.
|
8
25
|
# This should be optimized in the future potentially not to load all
|
@@ -2,7 +2,24 @@
|
|
2
2
|
module Mongoid # :nodoc:
|
3
3
|
module Relations #:nodoc:
|
4
4
|
module Cascading #:nodoc:
|
5
|
-
class Nullify
|
5
|
+
class Nullify
|
6
|
+
|
7
|
+
attr_accessor :document, :relation, :metadata
|
8
|
+
|
9
|
+
# Initialize the new cascade strategy, which will set up the relation
|
10
|
+
# and the metadata.
|
11
|
+
#
|
12
|
+
# @example Instantiate the strategy
|
13
|
+
# Strategy.new(document, metadata)
|
14
|
+
#
|
15
|
+
# @param [ Document ] document The document to cascade from.
|
16
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
17
|
+
#
|
18
|
+
# @return [ Strategy ] The new strategy.
|
19
|
+
def initialize(document, metadata)
|
20
|
+
@document, @metadata = document, metadata
|
21
|
+
@relation = document.send(metadata.name)
|
22
|
+
end
|
6
23
|
|
7
24
|
# This cascade does not delete the referenced relations, but instead
|
8
25
|
# sets the foreign key values to nil.
|
@@ -319,15 +319,13 @@ module Mongoid #:nodoc:
|
|
319
319
|
def substitute(replacement)
|
320
320
|
tap do |proxy|
|
321
321
|
if replacement
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
docs.push(doc) if doc.send(metadata.foreign_key) != base.id
|
328
|
-
end
|
329
|
-
proxy.concat(docs)
|
322
|
+
new_docs, docs = replacement.compact.uniq, []
|
323
|
+
new_ids = new_docs.map { |doc| doc.id }
|
324
|
+
remove_not_in(new_ids)
|
325
|
+
new_docs.each do |doc|
|
326
|
+
docs.push(doc) if doc.send(metadata.foreign_key) != base.id
|
330
327
|
end
|
328
|
+
proxy.concat(docs)
|
331
329
|
else
|
332
330
|
proxy.purge
|
333
331
|
end
|
@@ -142,10 +142,8 @@ module Mongoid # :nodoc:
|
|
142
142
|
# @since 2.0.0.rc.1
|
143
143
|
def substitute(replacement)
|
144
144
|
tap do |proxy|
|
145
|
-
|
146
|
-
|
147
|
-
proxy.push(replacement.compact.uniq) if replacement
|
148
|
-
end
|
145
|
+
proxy.purge
|
146
|
+
proxy.push(replacement.compact.uniq) unless replacement.blank?
|
149
147
|
end
|
150
148
|
end
|
151
149
|
|
@@ -41,6 +41,7 @@ module Mongoid #:nodoc:
|
|
41
41
|
#
|
42
42
|
# @since 1.0.0
|
43
43
|
def validate_each(document, attribute, value)
|
44
|
+
return unless document.send("#{attribute}_changed?")
|
44
45
|
if document.embedded?
|
45
46
|
return if skip_validation?(document)
|
46
47
|
relation = document._parent.send(document.metadata.name)
|
data/lib/mongoid/version.rb
CHANGED
data/lib/rails/mongoid.rb
CHANGED
@@ -15,22 +15,21 @@ module Rails #:nodoc:
|
|
15
15
|
#
|
16
16
|
# @since 2.1.0
|
17
17
|
def create_indexes(pattern)
|
18
|
-
logger = Logger.new($stdout)
|
19
18
|
Dir.glob(pattern).each do |file|
|
20
19
|
logger = Logger.new($stdout)
|
21
20
|
begin
|
22
21
|
model = determine_model(file)
|
23
|
-
if model
|
24
|
-
model.create_indexes
|
25
|
-
logger.info("Generated indexes for #{model}")
|
26
|
-
else
|
27
|
-
logger.info("Not a Mongoid parent model: #{file}")
|
28
|
-
end
|
29
22
|
rescue => e
|
30
|
-
logger.error
|
23
|
+
logger.error(%Q{Failed to determine model from #{file}:
|
31
24
|
#{e.class}:#{e.message}
|
32
25
|
#{e.backtrace.join("\n")}
|
33
|
-
}
|
26
|
+
})
|
27
|
+
end
|
28
|
+
if model
|
29
|
+
model.create_indexes
|
30
|
+
logger.info("Generated indexes for #{model}")
|
31
|
+
else
|
32
|
+
logger.info("Not a Mongoid parent model: #{file}")
|
34
33
|
end
|
35
34
|
end
|
36
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
16
|
-
requirement: &
|
16
|
+
requirement: &70092776306560 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70092776306560
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: tzinfo
|
27
|
-
requirement: &
|
27
|
+
requirement: &70092776305140 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.3.22
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70092776305140
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: mongo
|
38
|
-
requirement: &
|
38
|
+
requirement: &70092776302420 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.3'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70092776302420
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rdoc
|
49
|
-
requirement: &
|
49
|
+
requirement: &70092776301540 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 3.5.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70092776301540
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: bson_ext
|
60
|
-
requirement: &
|
60
|
+
requirement: &70092776300860 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '1.3'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70092776300860
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: mocha
|
71
|
-
requirement: &
|
71
|
+
requirement: &70092776296740 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 0.9.12
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70092776296740
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
requirement: &
|
82
|
+
requirement: &70092776295300 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '2.6'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70092776295300
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: watchr
|
93
|
-
requirement: &
|
93
|
+
requirement: &70092776293380 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ~>
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0.6'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70092776293380
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: ammeter
|
104
|
-
requirement: &
|
104
|
+
requirement: &70092776292500 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: 0.1.3
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70092776292500
|
113
113
|
description: Mongoid is an ODM (Object Document Mapper) Framework for MongoDB, written
|
114
114
|
in Ruby.
|
115
115
|
email:
|
@@ -332,7 +332,6 @@ files:
|
|
332
332
|
- lib/mongoid/relations/cascading/delete.rb
|
333
333
|
- lib/mongoid/relations/cascading/destroy.rb
|
334
334
|
- lib/mongoid/relations/cascading/nullify.rb
|
335
|
-
- lib/mongoid/relations/cascading/strategy.rb
|
336
335
|
- lib/mongoid/relations/cascading.rb
|
337
336
|
- lib/mongoid/relations/constraint.rb
|
338
337
|
- lib/mongoid/relations/conversions.rb
|
@@ -412,7 +411,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
412
411
|
version: '0'
|
413
412
|
segments:
|
414
413
|
- 0
|
415
|
-
hash:
|
414
|
+
hash: 1067878638816238851
|
416
415
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
417
416
|
none: false
|
418
417
|
requirements:
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module Mongoid # :nodoc:
|
3
|
-
module Relations #:nodoc:
|
4
|
-
module Cascading #:nodoc:
|
5
|
-
class Strategy
|
6
|
-
|
7
|
-
attr_accessor :document, :relation, :metadata
|
8
|
-
|
9
|
-
# Initialize the new cascade strategy, which will set up the relation
|
10
|
-
# and the metadata.
|
11
|
-
#
|
12
|
-
# @example Instantiate the strategy
|
13
|
-
# Strategy.new(document, metadata)
|
14
|
-
#
|
15
|
-
# @param [ Document ] document The document to cascade from.
|
16
|
-
# @param [ Metadata ] metadata The relation's metadata.
|
17
|
-
#
|
18
|
-
# @return [ Strategy ] The new strategy.
|
19
|
-
def initialize(document, metadata)
|
20
|
-
@document, @metadata = document, metadata
|
21
|
-
@relation = document.send(metadata.name)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|