mongoid 2.3.5 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/CHANGELOG.md +34 -176
  2. data/LICENSE +1 -1
  3. data/lib/config/locales/bg.yml +6 -0
  4. data/lib/config/locales/de.yml +6 -0
  5. data/lib/config/locales/en-GB.yml +8 -0
  6. data/lib/config/locales/en.yml +8 -0
  7. data/lib/config/locales/es.yml +9 -3
  8. data/lib/config/locales/fr.yml +6 -0
  9. data/lib/config/locales/hi.yml +6 -0
  10. data/lib/config/locales/hu.yml +6 -0
  11. data/lib/config/locales/id.yml +6 -0
  12. data/lib/config/locales/it.yml +6 -0
  13. data/lib/config/locales/ja.yml +6 -0
  14. data/lib/config/locales/kr.yml +6 -0
  15. data/lib/config/locales/nl.yml +8 -0
  16. data/lib/config/locales/pl.yml +6 -0
  17. data/lib/config/locales/pt-BR.yml +6 -0
  18. data/lib/config/locales/pt.yml +8 -2
  19. data/lib/config/locales/ro.yml +6 -0
  20. data/lib/config/locales/ru.yml +6 -0
  21. data/lib/config/locales/sv.yml +6 -0
  22. data/lib/config/locales/vi.yml +14 -8
  23. data/lib/config/locales/zh-CN.yml +6 -0
  24. data/lib/mongoid/atomic.rb +62 -13
  25. data/lib/mongoid/atomic/modifiers.rb +33 -1
  26. data/lib/mongoid/attributes.rb +5 -19
  27. data/lib/mongoid/callbacks.rb +2 -1
  28. data/lib/mongoid/collection.rb +2 -2
  29. data/lib/mongoid/collections/retry.rb +18 -6
  30. data/lib/mongoid/components.rb +2 -0
  31. data/lib/mongoid/config.rb +8 -63
  32. data/lib/mongoid/config/environment.rb +41 -0
  33. data/lib/mongoid/config/options.rb +74 -0
  34. data/lib/mongoid/contexts/enumerable.rb +0 -24
  35. data/lib/mongoid/contexts/mongo.rb +33 -3
  36. data/lib/mongoid/copyable.rb +1 -1
  37. data/lib/mongoid/criteria.rb +4 -2
  38. data/lib/mongoid/criterion/inclusion.rb +1 -16
  39. data/lib/mongoid/criterion/optional.rb +37 -10
  40. data/lib/mongoid/criterion/scoping.rb +83 -0
  41. data/lib/mongoid/criterion/selector.rb +9 -6
  42. data/lib/mongoid/default_scope.rb +1 -1
  43. data/lib/mongoid/dirty.rb +163 -29
  44. data/lib/mongoid/document.rb +58 -7
  45. data/lib/mongoid/errors.rb +2 -0
  46. data/lib/mongoid/errors/no_environment.rb +19 -0
  47. data/lib/mongoid/errors/scope_overwrite.rb +21 -0
  48. data/lib/mongoid/extensions.rb +6 -0
  49. data/lib/mongoid/extensions/array/deep_copy.rb +25 -0
  50. data/lib/mongoid/extensions/hash/deep_copy.rb +25 -0
  51. data/lib/mongoid/extensions/hash/scoping.rb +1 -1
  52. data/lib/mongoid/extensions/object/deep_copy.rb +21 -0
  53. data/lib/mongoid/extensions/proc/scoping.rb +2 -2
  54. data/lib/mongoid/extensions/symbol/inflections.rb +1 -0
  55. data/lib/mongoid/fields.rb +171 -104
  56. data/lib/mongoid/fields/{serializable → internal}/array.rb +33 -1
  57. data/lib/mongoid/fields/{serializable → internal}/big_decimal.rb +16 -1
  58. data/lib/mongoid/fields/{serializable → internal}/bignum.rb +1 -1
  59. data/lib/mongoid/fields/{serializable → internal}/binary.rb +1 -1
  60. data/lib/mongoid/fields/{serializable → internal}/boolean.rb +16 -1
  61. data/lib/mongoid/fields/{serializable → internal}/date.rb +1 -1
  62. data/lib/mongoid/fields/{serializable → internal}/date_time.rb +1 -1
  63. data/lib/mongoid/fields/{serializable → internal}/fixnum.rb +1 -1
  64. data/lib/mongoid/fields/{serializable → internal}/float.rb +16 -1
  65. data/lib/mongoid/fields/internal/foreign_keys/array.rb +74 -0
  66. data/lib/mongoid/fields/{serializable → internal}/foreign_keys/object.rb +11 -2
  67. data/lib/mongoid/fields/{serializable → internal}/hash.rb +1 -1
  68. data/lib/mongoid/fields/{serializable → internal}/integer.rb +16 -1
  69. data/lib/mongoid/fields/{serializable → internal}/localized.rb +23 -2
  70. data/lib/mongoid/fields/{serializable → internal}/nil_class.rb +16 -1
  71. data/lib/mongoid/fields/{serializable → internal}/object.rb +1 -1
  72. data/lib/mongoid/fields/{serializable → internal}/object_id.rb +16 -1
  73. data/lib/mongoid/fields/{serializable → internal}/range.rb +21 -2
  74. data/lib/mongoid/fields/{serializable → internal}/set.rb +16 -1
  75. data/lib/mongoid/fields/{serializable → internal}/string.rb +16 -1
  76. data/lib/mongoid/fields/{serializable → internal}/symbol.rb +17 -1
  77. data/lib/mongoid/fields/{serializable → internal}/time.rb +1 -1
  78. data/lib/mongoid/fields/{serializable → internal}/time_with_zone.rb +1 -1
  79. data/lib/mongoid/fields/{serializable → internal}/timekeeping.rb +16 -1
  80. data/lib/mongoid/fields/mappings.rb +8 -3
  81. data/lib/mongoid/fields/serializable.rb +34 -3
  82. data/lib/mongoid/hierarchy.rb +14 -14
  83. data/lib/mongoid/identity_map.rb +3 -2
  84. data/lib/mongoid/logger.rb +1 -7
  85. data/lib/mongoid/named_scope.rb +16 -12
  86. data/lib/mongoid/observer.rb +5 -1
  87. data/lib/mongoid/paranoia.rb +1 -0
  88. data/lib/mongoid/persistence.rb +11 -4
  89. data/lib/mongoid/persistence/atomic.rb +4 -1
  90. data/lib/mongoid/persistence/atomic/add_to_set.rb +17 -1
  91. data/lib/mongoid/persistence/atomic/sets.rb +1 -1
  92. data/lib/mongoid/railties/database.rake +1 -1
  93. data/lib/mongoid/relations.rb +1 -3
  94. data/lib/mongoid/relations/auto_save.rb +1 -1
  95. data/lib/mongoid/relations/builders.rb +1 -1
  96. data/lib/mongoid/relations/builders/embedded/many.rb +2 -6
  97. data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
  98. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  99. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +1 -1
  100. data/lib/mongoid/relations/cascading/delete.rb +1 -1
  101. data/lib/mongoid/relations/cyclic.rb +10 -6
  102. data/lib/mongoid/relations/embedded/atomic.rb +3 -3
  103. data/lib/mongoid/relations/embedded/many.rb +98 -20
  104. data/lib/mongoid/relations/macros.rb +2 -0
  105. data/lib/mongoid/relations/many.rb +13 -0
  106. data/lib/mongoid/relations/metadata.rb +3 -3
  107. data/lib/mongoid/relations/nested_builder.rb +4 -3
  108. data/lib/mongoid/relations/proxy.rb +0 -1
  109. data/lib/mongoid/relations/referenced/batch.rb +3 -2
  110. data/lib/mongoid/relations/referenced/in.rb +3 -3
  111. data/lib/mongoid/relations/referenced/many.rb +89 -10
  112. data/lib/mongoid/relations/referenced/many_to_many.rb +34 -43
  113. data/lib/mongoid/relations/referenced/one.rb +8 -4
  114. data/lib/mongoid/relations/synchronization.rb +22 -5
  115. data/lib/mongoid/threaded.rb +38 -276
  116. data/lib/mongoid/threaded/lifecycle.rb +18 -18
  117. data/lib/mongoid/timestamps/updated.rb +13 -3
  118. data/lib/mongoid/validations.rb +22 -1
  119. data/lib/mongoid/validations/presence.rb +40 -0
  120. data/lib/mongoid/validations/uniqueness.rb +14 -3
  121. data/lib/mongoid/version.rb +1 -1
  122. data/lib/mongoid/versioning.rb +6 -2
  123. data/lib/rails/mongoid.rb +7 -1
  124. metadata +64 -45
  125. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +0 -42
  126. data/lib/mongoid/relations/embedded/sort.rb +0 -31
@@ -27,8 +27,11 @@ module Mongoid #:nodoc:
27
27
  # @example Add only a unique value on the field.
28
28
  # person.add_to_set(:aliases, "Bond")
29
29
  #
30
+ # @example Add only the unique values to the field.
31
+ # person.add_to_set(:aliases, [ "Bond", "James" ])
32
+ #
30
33
  # @param [ Symbol ] field The name of the field.
31
- # @param [ Object ] value The value to add.
34
+ # @param [ Object, Array<Object> ] value The value or values to add.
32
35
  # @param [ Hash ] options The mongo persistence options.
33
36
  #
34
37
  # @return [ Array<Object> ] The new value of the field.
@@ -20,7 +20,9 @@ module Mongoid #:nodoc:
20
20
  prepare do
21
21
  document[field] = [] unless document[field]
22
22
  values = document.send(field)
23
- values.push(value) unless values.include?(value)
23
+ Array.wrap(value).each do |val|
24
+ values.push(val) unless values.include?(val)
25
+ end
24
26
  values.tap do
25
27
  if document.persisted?
26
28
  collection.update(document.atomic_selector, operation("$addToSet"), options)
@@ -29,6 +31,20 @@ module Mongoid #:nodoc:
29
31
  end
30
32
  end
31
33
  end
34
+
35
+ # Get the atomic operation to perform.
36
+ #
37
+ # @example Get the operation.
38
+ # add_to_set.operation("$addToSet")
39
+ #
40
+ # @param [ String ] modifier The modifier to use.
41
+ #
42
+ # @return [ Hash ] The atomic operation for the field and addition.
43
+ #
44
+ # @since 2.0.0
45
+ def operation(modifier)
46
+ { modifier => { path => value.is_a?(Array) ? { "$each" => value } : value}}
47
+ end
32
48
  end
33
49
  end
34
50
  end
@@ -17,7 +17,7 @@ module Mongoid #:nodoc:
17
17
  # @ssete 2.0.0
18
18
  def persist
19
19
  prepare do
20
- value ? document[field] = value : @value = document[field]
20
+ document[field] = value
21
21
  document[field].tap do
22
22
  collection.update(document.atomic_selector, operation("$set"), options)
23
23
  document.remove_change(field)
@@ -78,7 +78,7 @@ namespace :db do
78
78
  desc 'Create the indexes defined on your mongoid models'
79
79
  task :create_indexes => :environment do
80
80
  engines_models_paths = Rails.application.railties.engines.map do |engine|
81
- engine.paths["app/models"].paths
81
+ engine.paths["app/models"].expanded
82
82
  end
83
83
  root_models_paths = Rails.application.paths["app/models"]
84
84
  models_paths = engines_models_paths.push(root_models_paths).flatten
@@ -44,9 +44,7 @@ module Mongoid # :nodoc:
44
44
  include Reflections
45
45
  include Synchronization
46
46
 
47
- included do
48
- attr_accessor :metadata
49
- end
47
+ attr_accessor :metadata
50
48
 
51
49
  # Determine if the document itself is embedded in another document via the
52
50
  # proper channels. (If it has a parent document.)
@@ -25,7 +25,7 @@ module Mongoid # :nodoc:
25
25
  set_callback :save, :after do |document|
26
26
  relation = document.send(metadata.name)
27
27
  if relation
28
- (relation.do_or_do_not(:in_memory) || relation.to_a).each do |doc|
28
+ (relation.do_or_do_not(:in_memory) || Array.wrap(relation)).each do |doc|
29
29
  doc.save
30
30
  end
31
31
  end
@@ -68,7 +68,7 @@ module Mongoid # :nodoc:
68
68
  attributes, options = parse_args(*args)
69
69
  document = Factory.build(metadata.klass, attributes, options)
70
70
  _building do
71
- send("#{name}=", document)
71
+ send("#{name}=", document).tap {|child| child.run_callbacks(:build) }
72
72
  end
73
73
  end
74
74
  end
@@ -1,12 +1,9 @@
1
1
  # encoding: utf-8
2
- require "mongoid/relations/embedded/sort"
3
-
4
2
  module Mongoid # :nodoc:
5
3
  module Relations #:nodoc:
6
4
  module Builders #:nodoc:
7
5
  module Embedded #:nodoc:
8
6
  class Many < Builder #:nodoc:
9
- include Relations::Embedded::Sort
10
7
 
11
8
  # Builds the document out of the attributes using the provided
12
9
  # metadata on the relation. Instantiates through the factory in order
@@ -25,12 +22,11 @@ module Mongoid # :nodoc:
25
22
  [].tap do |docs|
26
23
  object.each do |attrs|
27
24
  if _loading?
28
- docs << Factory.from_db(klass, attrs)
25
+ docs.push(Factory.from_db(klass, attrs))
29
26
  else
30
- docs << Factory.build(klass, attrs)
27
+ docs.push(Factory.build(klass, attrs))
31
28
  end
32
29
  end
33
- sort_documents!(docs, metadata) if metadata.order
34
30
  end
35
31
  end
36
32
  end
@@ -92,7 +92,7 @@ module Mongoid # :nodoc:
92
92
  def process(parent, attrs)
93
93
  return if reject?(parent, attrs)
94
94
  if id = attrs.extract_id
95
- doc = existing.find(convert_id(id))
95
+ doc = existing.find(convert_id(existing.first.class, id))
96
96
  if destroyable?(attrs)
97
97
  existing.delete(doc)
98
98
  doc.destroy unless doc.embedded?
@@ -69,7 +69,7 @@ module Mongoid # :nodoc:
69
69
  #
70
70
  # True if the id part of the logic will allow an update.
71
71
  def acceptable_id?
72
- id = convert_id(attributes[:id])
72
+ id = convert_id(existing.class, attributes[:id])
73
73
  existing.id == id || id.nil? || (existing.id != id && update_only?)
74
74
  end
75
75
 
@@ -16,7 +16,7 @@ module Mongoid # :nodoc:
16
16
  # @return [ Array<Document> ] The documents.
17
17
  def build(type = nil)
18
18
  return object.try(:dup) unless query?
19
- metadata.criteria(object)
19
+ metadata.criteria(object || [])
20
20
  end
21
21
 
22
22
  # Do we need to perform a database query? It will be so if the object we
@@ -11,7 +11,7 @@ module Mongoid # :nodoc:
11
11
  # @example Perform the cascading delete.
12
12
  # strategy.cascade
13
13
  def cascade
14
- relation.to_a.each { |doc| doc.delete } if relation
14
+ Array.wrap(relation).each { |doc| doc.delete } if relation
15
15
  end
16
16
  end
17
17
  end
@@ -35,9 +35,11 @@ module Mongoid # :nodoc:
35
35
  # or its children.
36
36
  #
37
37
  # @since 2.0.0.rc.1
38
- def recursively_embeds_many
39
- self.cyclic = true
40
- embeds_many cyclic_child_name, :class_name => self.name, :cyclic => true
38
+ def recursively_embeds_many(options = {})
39
+ embeds_many(
40
+ cyclic_child_name,
41
+ options.merge(:class_name => self.name, :cyclic => true)
42
+ )
41
43
  embedded_in cyclic_parent_name, :class_name => self.name, :cyclic => true
42
44
  end
43
45
 
@@ -63,9 +65,11 @@ module Mongoid # :nodoc:
63
65
  # or its children.
64
66
  #
65
67
  # @since 2.0.0.rc.1
66
- def recursively_embeds_one
67
- self.cyclic = true
68
- embeds_one cyclic_child_name(false), :class_name => self.name, :cyclic => true
68
+ def recursively_embeds_one(options = {})
69
+ embeds_one(
70
+ cyclic_child_name(false),
71
+ options.merge(:class_name => self.name, :cyclic => true)
72
+ )
69
73
  embedded_in cyclic_parent_name, :class_name => self.name, :cyclic => true
70
74
  end
71
75
 
@@ -55,13 +55,13 @@ module Mongoid #:nodoc:
55
55
  #
56
56
  # @since 2.0.0
57
57
  def atomically(modifier, &block)
58
- updater = Threaded.update_consumer(collection_name) ||
59
- Threaded.set_update_consumer(collection_name, MODIFIERS[modifier].new)
58
+ updater = Threaded.update_consumer(root_class) ||
59
+ Threaded.set_update_consumer(root_class, MODIFIERS[modifier].new)
60
60
  count_executions do
61
61
  block.call if block
62
62
  end.tap do
63
63
  if @executions.zero?
64
- Threaded.set_update_consumer(collection_name, nil)
64
+ Threaded.set_update_consumer(root_class, nil)
65
65
  updater.execute(collection)
66
66
  end
67
67
  end
@@ -17,21 +17,42 @@ module Mongoid # :nodoc:
17
17
  # @example Push a document.
18
18
  # person.addresses.push(address)
19
19
  #
20
+ # @param [ Document, Array<Document> ] *args Any number of documents.
21
+ def <<(*args)
22
+ docs = args.flatten
23
+ return concat(docs) if docs.size > 1
24
+ if doc = docs.first
25
+ append(doc)
26
+ doc.save if persistable? && !_assigning?
27
+ end
28
+ end
29
+ alias :push :<<
30
+
31
+ # Appends an array of documents to the relation. Performs a batch
32
+ # insert of the documents instead of persisting one at a time.
33
+ #
34
+ # @note When performing batch inserts the *after* callbacks will get
35
+ # executed before the documents have actually been persisted to the
36
+ # database due to an issue with Active Support's callback system - we
37
+ # cannot explicitly fire the after callbacks by themselves.
38
+ #
20
39
  # @example Concat with other documents.
21
40
  # person.addresses.concat([ address_one, address_two ])
22
41
  #
23
- # @param [ Document, Array<Document> ] *args Any number of documents.
24
- def <<(*args)
42
+ # @param [ Array<Document> ] documents The docs to add.
43
+ #
44
+ # @return [ Array<Document> ] The documents.
45
+ #
46
+ # @since 2.4.0
47
+ def concat(documents)
25
48
  atomically(:$pushAll) do
26
- args.flatten.each do |doc|
49
+ documents.each do |doc|
27
50
  next unless doc
28
51
  append(doc)
29
- doc.save if persistable? && !_assigning?
52
+ doc.save if persistable?
30
53
  end
31
54
  end
32
55
  end
33
- alias :concat :<<
34
- alias :push :<<
35
56
 
36
57
  # Builds a new document in the relation and appends it to the target.
37
58
  # Takes an optional type if you want to specify a subclass.
@@ -58,6 +79,7 @@ module Mongoid # :nodoc:
58
79
  doc.identify
59
80
  append(doc)
60
81
  yield(doc) if block_given?
82
+ doc.run_callbacks(:build) { doc }
61
83
  end
62
84
  end
63
85
  alias :new :build
@@ -71,7 +93,10 @@ module Mongoid # :nodoc:
71
93
  # @return [ Many ] The empty relation.
72
94
  def clear
73
95
  tap do |proxy|
74
- atomically(:$unset) { proxy.delete_all }
96
+ atomically(:$unset) do
97
+ proxy.delete_all
98
+ _unscoped.clear
99
+ end
75
100
  end
76
101
  end
77
102
 
@@ -145,8 +170,9 @@ module Mongoid # :nodoc:
145
170
  # @since 2.0.0.rc.1
146
171
  def delete(document)
147
172
  target.delete_one(document).tap do |doc|
173
+ _unscoped.delete_one(doc)
148
174
  if doc && !_binding?
149
- if _assigning?
175
+ if _assigning? && !doc.paranoid?
150
176
  base.add_atomic_pull(doc)
151
177
  else
152
178
  doc.delete(:suppress => true)
@@ -224,6 +250,8 @@ module Mongoid # :nodoc:
224
250
  integrate(doc)
225
251
  doc._index = index
226
252
  end
253
+ @_unscoped = target.dup
254
+ @target = scope(target)
227
255
  end
228
256
  end
229
257
 
@@ -263,7 +291,9 @@ module Mongoid # :nodoc:
263
291
  if replacement.first.is_a?(Hash)
264
292
  replacement = Many.builder(base, metadata, replacement).build
265
293
  end
266
- proxy.target = replacement.compact
294
+ docs = replacement.compact
295
+ proxy.target = docs
296
+ self._unscoped = docs.dup
267
297
  if _assigning?
268
298
  base.delayed_atomic_sets[metadata.name.to_s] = proxy.as_document
269
299
  end
@@ -287,23 +317,25 @@ module Mongoid # :nodoc:
287
317
  # @since 2.0.0.rc.1
288
318
  def as_document
289
319
  [].tap do |attributes|
290
- target.each do |doc|
291
- attributes << doc.as_document
320
+ _unscoped.each do |doc|
321
+ attributes.push(doc.as_document)
292
322
  end
293
323
  end
294
324
  end
295
325
 
296
- # Get a criteria for the embedded documents without the default scoping
297
- # applied.
326
+ # Return the relation with all previous scoping removed. This is the
327
+ # exact representation of the docs in the database.
298
328
  #
299
- # @example Get the unscoped criteria.
329
+ # @example Get the unscoped documents.
300
330
  # person.addresses.unscoped
301
331
  #
302
- # @return [ Criteria ] The unscoped criteria.
332
+ # @return [ Criteria ] The unscoped relation.
303
333
  #
304
- # @since 2.2.1
334
+ # @since 2.4.0
305
335
  def unscoped
306
- criteria(false)
336
+ klass.criteria(true, false).tap do |criterion|
337
+ criterion.documents = _unscoped
338
+ end
307
339
  end
308
340
 
309
341
  private
@@ -319,6 +351,7 @@ module Mongoid # :nodoc:
319
351
  # @since 2.0.0.rc.1
320
352
  def append(document)
321
353
  target.push(document)
354
+ _unscoped.push(document)
322
355
  integrate(document)
323
356
  document._index = target.size - 1
324
357
  end
@@ -344,8 +377,8 @@ module Mongoid # :nodoc:
344
377
  # relation.criteria
345
378
  #
346
379
  # @return [ Criteria ] A new criteria.
347
- def criteria(scoped = true)
348
- klass.criteria(true, scoped).tap do |criterion|
380
+ def criteria
381
+ klass.criteria(true).tap do |criterion|
349
382
  criterion.documents = target
350
383
  end
351
384
  end
@@ -402,11 +435,29 @@ module Mongoid # :nodoc:
402
435
  #
403
436
  # @since 2.0.0.rc.1
404
437
  def reindex
405
- target.each_with_index do |doc, index|
438
+ _unscoped.each_with_index do |doc, index|
406
439
  doc._index = index
407
440
  end
408
441
  end
409
442
 
443
+ # Apply the metadata ordering or the default scoping to the provided
444
+ # documents.
445
+ #
446
+ # @example Apply scoping.
447
+ # person.addresses.scope(target)
448
+ #
449
+ # @param [ Array<Document> ] docs The documents to scope.
450
+ #
451
+ # @return [ Array<Document> ] The scoped docs.
452
+ #
453
+ # @since 2.4.0
454
+ def scope(docs)
455
+ return docs unless metadata.order || metadata.klass.default_scoping?
456
+ metadata.klass.criteria(true).order_by(metadata.order).tap do |crit|
457
+ crit.documents = docs
458
+ end.entries
459
+ end
460
+
410
461
  # Remove all documents from the relation, either with a delete or a
411
462
  # destroy depending on what this was called through.
412
463
  #
@@ -422,6 +473,7 @@ module Mongoid # :nodoc:
422
473
  criteria.size.tap do
423
474
  criteria.each do |doc|
424
475
  target.delete_one(doc)
476
+ _unscoped.delete_one(doc)
425
477
  doc.send(method, :suppress => true) unless _assigning?
426
478
  unbind_one(doc)
427
479
  end
@@ -429,6 +481,32 @@ module Mongoid # :nodoc:
429
481
  end
430
482
  end
431
483
 
484
+ # Get the internal unscoped documents.
485
+ #
486
+ # @example Get the unscoped documents.
487
+ # relation._unscoped
488
+ #
489
+ # @return [ Array<Document> ] The unscoped documents.
490
+ #
491
+ # @since 2.4.0
492
+ def _unscoped
493
+ @_unscoped ||= []
494
+ end
495
+
496
+ # Set the internal unscoped documents.
497
+ #
498
+ # @example Set the unscoped documents.
499
+ # relation._unscoped = docs
500
+ #
501
+ # @param [ Array<Document> ] docs The documents.
502
+ #
503
+ # @return [ Array<Document ] The unscoped docs.
504
+ #
505
+ # @since 2.4.0
506
+ def _unscoped=(docs)
507
+ @_unscoped = docs
508
+ end
509
+
432
510
  class << self
433
511
 
434
512
  # Return the builder that is responsible for generating the documents
@@ -76,6 +76,7 @@ module Mongoid # :nodoc:
76
76
  # @param [ Proc ] block Optional block for defining extensions.
77
77
  def embeds_many(name, options = {}, &block)
78
78
  characterize(name, Embedded::Many, options, &block).tap do |meta|
79
+ self.cyclic = true if options[:cyclic]
79
80
  relate(name, meta)
80
81
  validates_relation(meta)
81
82
  end
@@ -102,6 +103,7 @@ module Mongoid # :nodoc:
102
103
  # @param [ Proc ] block Optional block for defining extensions.
103
104
  def embeds_one(name, options = {}, &block)
104
105
  characterize(name, Embedded::One, options, &block).tap do |meta|
106
+ self.cyclic = true if options[:cyclic]
105
107
  relate(name, meta)
106
108
  builder(name, meta).creator(name, meta)
107
109
  validates_relation(meta)