mongoid 2.3.5 → 2.4.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.
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)