mongoid 2.2.0 → 2.2.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.
Files changed (52) hide show
  1. data/CHANGELOG.md +57 -3
  2. data/Rakefile +1 -1
  3. data/lib/mongoid/atomic/modifiers.rb +2 -1
  4. data/lib/mongoid/config.rb +0 -1
  5. data/lib/mongoid/config/replset_database.rb +2 -2
  6. data/lib/mongoid/contexts/mongo.rb +14 -5
  7. data/lib/mongoid/criteria.rb +4 -4
  8. data/lib/mongoid/criterion/inclusion.rb +16 -1
  9. data/lib/mongoid/document.rb +2 -4
  10. data/lib/mongoid/extensions.rb +7 -0
  11. data/lib/mongoid/extensions/integer/checks.rb +23 -0
  12. data/lib/mongoid/extensions/object/yoda.rb +16 -0
  13. data/lib/mongoid/extensions/object_id/conversions.rb +1 -1
  14. data/lib/mongoid/extensions/string/checks.rb +24 -0
  15. data/lib/mongoid/extensions/string/inflections.rb +1 -1
  16. data/lib/mongoid/fields.rb +4 -2
  17. data/lib/mongoid/fields/serializable.rb +26 -18
  18. data/lib/mongoid/fields/serializable/array.rb +0 -1
  19. data/lib/mongoid/fields/serializable/boolean.rb +0 -1
  20. data/lib/mongoid/fields/serializable/float.rb +0 -1
  21. data/lib/mongoid/fields/serializable/integer.rb +1 -2
  22. data/lib/mongoid/fields/serializable/object_id.rb +0 -1
  23. data/lib/mongoid/fields/serializable/string.rb +0 -1
  24. data/lib/mongoid/fields/serializable/symbol.rb +0 -1
  25. data/lib/mongoid/matchers/strategies.rb +25 -2
  26. data/lib/mongoid/nested_attributes.rb +1 -1
  27. data/lib/mongoid/persistence/atomic.rb +2 -2
  28. data/lib/mongoid/persistence/atomic/{set.rb → sets.rb} +1 -1
  29. data/lib/mongoid/persistence/deletion.rb +1 -1
  30. data/lib/mongoid/relations/bindings/referenced/in.rb +5 -5
  31. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -4
  32. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +2 -2
  33. data/lib/mongoid/relations/bindings/referenced/one.rb +4 -4
  34. data/lib/mongoid/relations/builder.rb +1 -2
  35. data/lib/mongoid/relations/builders/nested_attributes/many.rb +5 -4
  36. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  37. data/lib/mongoid/relations/builders/referenced/many.rb +4 -2
  38. data/lib/mongoid/relations/cascading/destroy.rb +8 -1
  39. data/lib/mongoid/relations/embedded/in.rb +1 -1
  40. data/lib/mongoid/relations/embedded/many.rb +15 -2
  41. data/lib/mongoid/relations/embedded/one.rb +1 -1
  42. data/lib/mongoid/relations/nested_builder.rb +11 -4
  43. data/lib/mongoid/relations/referenced/many.rb +4 -2
  44. data/lib/mongoid/relations/referenced/many_to_many.rb +2 -1
  45. data/lib/mongoid/relations/synchronization.rb +39 -2
  46. data/lib/mongoid/relations/targets/enumerable.rb +2 -2
  47. data/lib/mongoid/serialization.rb +1 -1
  48. data/lib/mongoid/state.rb +1 -1
  49. data/lib/mongoid/version.rb +1 -1
  50. data/lib/mongoid/versioning.rb +15 -1
  51. metadata +26 -22
  52. data/lib/mongoid/criterion/unconvertable.rb +0 -20
@@ -21,7 +21,6 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  raise_or_return(object)
23
23
  end
24
- alias :set :serialize
25
24
 
26
25
  protected
27
26
 
@@ -37,7 +37,6 @@ module Mongoid #:nodoc:
37
37
  object = MAPPINGS[object]
38
38
  object.nil? ? nil : object
39
39
  end
40
- alias :set :serialize
41
40
  end
42
41
  end
43
42
  end
@@ -26,7 +26,6 @@ module Mongoid #:nodoc:
26
26
  object
27
27
  end
28
28
  end
29
- alias :set :serialize
30
29
  end
31
30
  end
32
31
  end
@@ -21,12 +21,11 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  return nil if object.blank?
23
23
  begin
24
- object.to_s =~ /\./ ? Float(object) : Integer(object)
24
+ object.to_s =~ /(^[-+]?[0-9]+$)|(\.0+)$/ ? Integer(object) : Float(object)
25
25
  rescue
26
26
  object
27
27
  end
28
28
  end
29
- alias :set :serialize
30
29
  end
31
30
  end
32
31
  end
@@ -25,7 +25,6 @@ module Mongoid #:nodoc:
25
25
  object
26
26
  end
27
27
  end
28
- alias :set :serialize
29
28
  end
30
29
  end
31
30
  end
@@ -21,7 +21,6 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  object.try(:to_s)
23
23
  end
24
- alias :set :serialize
25
24
  end
26
25
  end
27
26
  end
@@ -21,7 +21,6 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  object.blank? ? nil : object.to_sym
23
23
  end
24
- alias :set :serialize
25
24
  end
26
25
  end
27
26
  end
@@ -49,15 +49,38 @@ module Mongoid #:nodoc:
49
49
  # @since 2.0.0.rc.7
50
50
  def matcher(document, key, value)
51
51
  if value.is_a?(Hash)
52
- MATCHERS[value.keys.first].new(document.attributes[key.to_s])
52
+ MATCHERS[value.keys.first].new(extract_attribute(document, key))
53
53
  else
54
54
  if key == "$or"
55
55
  Matchers::Or.new(value, document)
56
56
  else
57
- Default.new(document.attributes[key.to_s])
57
+ Default.new(extract_attribute(document, key))
58
58
  end
59
59
  end
60
60
  end
61
+
62
+ private
63
+
64
+ # Extract the attribute from the key, being smarter about dot notation.
65
+ #
66
+ # @example Extract the attribute.
67
+ # strategy.extract_attribute(doc, "info.field")
68
+ #
69
+ # @param [ Document ] document The document.
70
+ # @param [ String ] key The key.
71
+ #
72
+ # @return [ Object ] The value of the attribute.
73
+ #
74
+ # @since 2.2.1
75
+ def extract_attribute(document, key)
76
+ if (key_string = key.to_s) =~ /.+\..+/
77
+ key_string.split('.').inject(document.attributes) do |attribs, key|
78
+ attribs.try(:[], key)
79
+ end
80
+ else
81
+ document.attributes[key_string]
82
+ end
83
+ end
61
84
  end
62
85
  end
63
86
  end
@@ -45,7 +45,7 @@ module Mongoid #:nodoc:
45
45
  # by a hash of options.
46
46
  #
47
47
  # @option *args [ true, false ] :allow_destroy Can deletion occur?
48
- # @option *args [ Proc ] :reject_if Block to reject documents with.
48
+ # @option *args [ Proc, Symbol ] :reject_if Block or symbol pointing to a class method to reject documents with.
49
49
  # @option *args [ Integer ] :limit The max number to create.
50
50
  # @option *args [ true, false ] :update_only Only update existing docs.
51
51
  def accepts_nested_attributes_for(*args)
@@ -9,7 +9,7 @@ require "mongoid/persistence/atomic/pull_all"
9
9
  require "mongoid/persistence/atomic/push"
10
10
  require "mongoid/persistence/atomic/push_all"
11
11
  require "mongoid/persistence/atomic/rename"
12
- require "mongoid/persistence/atomic/set"
12
+ require "mongoid/persistence/atomic/sets"
13
13
  require "mongoid/persistence/atomic/unset"
14
14
 
15
15
  module Mongoid #:nodoc:
@@ -201,7 +201,7 @@ module Mongoid #:nodoc:
201
201
  #
202
202
  # @since 2.1.0
203
203
  def set(field, value = nil, options = {})
204
- Set.new(self, field, value, options).persist
204
+ Sets.new(self, field, value, options).persist
205
205
  end
206
206
 
207
207
  # Performs the atomic $unset on the supplied field.
@@ -4,7 +4,7 @@ module Mongoid #:nodoc:
4
4
  module Atomic #:nodoc:
5
5
 
6
6
  # This class provides atomic $set behaviour.
7
- class Set
7
+ class Sets
8
8
  include Operation
9
9
 
10
10
  # Sends the atomic $set operation to the database.
@@ -19,10 +19,10 @@ module Mongoid #:nodoc:
19
19
  #
20
20
  # @since 2.1.0
21
21
  def prepare(&block)
22
+ document.cascade!
22
23
  yield(document)
23
24
  document.freeze
24
25
  document.destroyed = true
25
- document.cascade!
26
26
  IdentityMap.remove(document)
27
27
  Threaded.clear_safety_options!
28
28
  true
@@ -22,13 +22,13 @@ module Mongoid # :nodoc:
22
22
  unless binding?
23
23
  binding do
24
24
  inverse = metadata.inverse(target)
25
- base.send(metadata.foreign_key_setter, target.id)
25
+ base.you_must(metadata.foreign_key_setter, target.id)
26
26
  if metadata.inverse_type
27
- base.send(metadata.inverse_type_setter, target.class.model_name)
27
+ base.you_must(metadata.inverse_type_setter, target.class.model_name)
28
28
  end
29
29
  if inverse
30
30
  inverse_metadata = metadata.inverse_metadata(target)
31
- if inverse_metadata != metadata
31
+ if inverse_metadata != metadata && !inverse_metadata.nil?
32
32
  base.metadata = inverse_metadata
33
33
  if base.referenced_many?
34
34
  target.send(inverse).push(base)
@@ -54,9 +54,9 @@ module Mongoid # :nodoc:
54
54
  unless binding?
55
55
  binding do
56
56
  inverse = metadata.inverse(target)
57
- base.send(metadata.foreign_key_setter, nil)
57
+ base.you_must(metadata.foreign_key_setter, nil)
58
58
  if metadata.inverse_type
59
- base.send(metadata.inverse_type_setter, nil)
59
+ base.you_must(metadata.inverse_type_setter, nil)
60
60
  end
61
61
  if inverse
62
62
  if base.referenced_many?
@@ -19,9 +19,9 @@ module Mongoid # :nodoc:
19
19
  def bind_one(doc)
20
20
  unless binding?
21
21
  binding do
22
- doc.send(metadata.foreign_key_setter, base.id)
22
+ doc.you_must(metadata.foreign_key_setter, base.id)
23
23
  if metadata.type
24
- doc.send(metadata.type_setter, base.class.model_name)
24
+ doc.you_must(metadata.type_setter, base.class.model_name)
25
25
  end
26
26
  doc.send(metadata.inverse_setter, base)
27
27
  end
@@ -39,9 +39,9 @@ module Mongoid # :nodoc:
39
39
  def unbind_one(doc)
40
40
  unless binding?
41
41
  binding do
42
- doc.send(metadata.foreign_key_setter, nil)
42
+ doc.you_must(metadata.foreign_key_setter, nil)
43
43
  if metadata.type
44
- doc.send(metadata.type_setter, nil)
44
+ doc.you_must(metadata.type_setter, nil)
45
45
  end
46
46
  doc.send(metadata.inverse_setter, nil)
47
47
  end
@@ -19,7 +19,7 @@ module Mongoid # :nodoc:
19
19
  def bind_one(doc)
20
20
  unless binding?
21
21
  binding do
22
- inverse_keys = doc.do_or_do_not(metadata.inverse_foreign_key)
22
+ inverse_keys = doc.you_must(metadata.inverse_foreign_key)
23
23
  inverse_keys.push(base.id) if inverse_keys
24
24
  base.synced[metadata.foreign_key] = true
25
25
  doc.synced[metadata.inverse_foreign_key] = true
@@ -37,7 +37,7 @@ module Mongoid # :nodoc:
37
37
  unless binding?
38
38
  binding do
39
39
  base.send(metadata.foreign_key).delete_one(doc.id)
40
- inverse_keys = doc.do_or_do_not(metadata.inverse_foreign_key)
40
+ inverse_keys = doc.you_must(metadata.inverse_foreign_key)
41
41
  inverse_keys.delete_one(base.id) if inverse_keys
42
42
  base.synced[metadata.foreign_key] = true
43
43
  doc.synced[metadata.inverse_foreign_key] = true
@@ -21,10 +21,10 @@ module Mongoid # :nodoc:
21
21
  def bind
22
22
  unless binding?
23
23
  binding do
24
- target.send(metadata.foreign_key_setter, base.id)
24
+ target.you_must(metadata.foreign_key_setter, base.id)
25
25
  target.send(metadata.inverse_setter, base)
26
26
  if metadata.type
27
- target.send(metadata.type_setter, base.class.model_name)
27
+ target.you_must(metadata.type_setter, base.class.model_name)
28
28
  end
29
29
  end
30
30
  end
@@ -42,10 +42,10 @@ module Mongoid # :nodoc:
42
42
  def unbind
43
43
  unless binding?
44
44
  binding do
45
- target.send(metadata.foreign_key_setter, nil)
45
+ target.you_must(metadata.foreign_key_setter, nil)
46
46
  target.send(metadata.inverse_setter, nil)
47
47
  if metadata.type
48
- target.send(metadata.type_setter, nil)
48
+ target.you_must(metadata.type_setter, nil)
49
49
  end
50
50
  end
51
51
  end
@@ -35,8 +35,7 @@ module Mongoid # :nodoc:
35
35
  #
36
36
  # @since 2.0.0.rc.1
37
37
  def query?
38
- return true unless object.respond_to?(:to_a)
39
- obj = object.to_a.first
38
+ obj = Array(object).first
40
39
  !obj.is_a?(Mongoid::Document) && !obj.nil?
41
40
  end
42
41
  end
@@ -25,9 +25,9 @@ module Mongoid # :nodoc:
25
25
  end
26
26
  attributes.each do |attrs|
27
27
  if attrs.respond_to?(:with_indifferent_access)
28
- process(attrs)
28
+ process(parent, attrs)
29
29
  else
30
- process(attrs[1])
30
+ process(parent, attrs[1])
31
31
  end
32
32
  end
33
33
  end
@@ -89,12 +89,13 @@ module Mongoid # :nodoc:
89
89
  # builder.process({ "id" => 1, "street" => "Bond" })
90
90
  #
91
91
  # @param [ Hash ] attrs The single document attributes to process.
92
- def process(attrs)
93
- return if reject?(attrs)
92
+ def process(parent, attrs)
93
+ return if reject?(parent, attrs)
94
94
  if id = attrs["id"] || attrs["_id"]
95
95
  doc = existing.find(convert_id(id))
96
96
  if destroyable?(attrs)
97
97
  existing.delete(doc)
98
+ doc.destroy unless doc.embedded?
98
99
  else
99
100
  metadata.embedded? ? doc.attributes = attrs : doc.update_attributes(attrs)
100
101
  end
@@ -22,7 +22,7 @@ module Mongoid # :nodoc:
22
22
  #
23
23
  # parent: The parent document of the relation.
24
24
  def build(parent)
25
- return if reject?(attributes)
25
+ return if reject?(parent, attributes)
26
26
  @existing = parent.send(metadata.name)
27
27
  if update?
28
28
  existing.attributes = attributes
@@ -29,7 +29,7 @@ module Mongoid # :nodoc:
29
29
  # @example Get the value.
30
30
  # builder.convertable
31
31
  #
32
- # @return [ String, Unconvertable, BSON::ObjectId ] The string or object id.
32
+ # @return [ String, BSON::ObjectId ] The string or object id.
33
33
  #
34
34
  # @since 2.0.2
35
35
  def convertable(metadata, object)
@@ -37,7 +37,9 @@ module Mongoid # :nodoc:
37
37
  if inverse.using_object_ids? || object.is_a?(BSON::ObjectId)
38
38
  object
39
39
  else
40
- Criterion::Unconvertable.new(object)
40
+ object.tap do |obj|
41
+ obj.unconvertable_to_bson = true if obj.is_a?(String)
42
+ end
41
43
  end
42
44
  end
43
45
  end
@@ -11,7 +11,14 @@ module Mongoid # :nodoc:
11
11
  # @example Perform the cascading destroy.
12
12
  # strategy.cascade
13
13
  def cascade
14
- relation.to_a.each { |doc| doc.destroy } if relation
14
+ if relation
15
+ if relation.is_a?(Enumerable)
16
+ relation.entries
17
+ relation.each { |doc| doc.destroy }
18
+ else
19
+ relation.destroy
20
+ end
21
+ end
15
22
  end
16
23
  end
17
24
  end
@@ -41,7 +41,7 @@ module Mongoid # :nodoc:
41
41
  tap do |proxy|
42
42
  proxy.unbind_one
43
43
  unless replacement
44
- base.delete unless binding?
44
+ base.delete if persistable?
45
45
  return nil
46
46
  end
47
47
  base.new_record = true
@@ -268,6 +268,19 @@ module Mongoid # :nodoc:
268
268
  end
269
269
  end
270
270
 
271
+ # Get a criteria for the embedded documents without the default scoping
272
+ # applied.
273
+ #
274
+ # @example Get the unscoped criteria.
275
+ # person.addresses.unscoped
276
+ #
277
+ # @return [ Criteria ] The unscoped criteria.
278
+ #
279
+ # @since 2.2.1
280
+ def unscoped
281
+ criteria(false)
282
+ end
283
+
271
284
  private
272
285
 
273
286
  # Appends the document to the target array, updating the index on the
@@ -306,8 +319,8 @@ module Mongoid # :nodoc:
306
319
  # relation.criteria
307
320
  #
308
321
  # @return [ Criteria ] A new criteria.
309
- def criteria
310
- klass.criteria(true).tap do |criterion|
322
+ def criteria(scoped = true)
323
+ klass.criteria(true, scoped).tap do |criterion|
311
324
  criterion.documents = target
312
325
  end
313
326
  end
@@ -39,7 +39,7 @@ module Mongoid # :nodoc:
39
39
  if assigning?
40
40
  base.atomic_unsets.push(proxy.atomic_path)
41
41
  else
42
- proxy.delete
42
+ proxy.delete if persistable?
43
43
  end
44
44
  proxy.unbind_one
45
45
  return nil unless replacement
@@ -25,14 +25,21 @@ module Mongoid # :nodoc:
25
25
  # @example Is there a reject proc?
26
26
  # builder.reject?
27
27
  #
28
+ # @param The parent document of the relation
28
29
  # @param [ Hash ] attrs The attributes to check for rejection.
29
30
  #
30
- # @return [ true, false ] True and call proc if rejectable, false if not.
31
+ # @return [ true, false ] True and call proc or method if rejectable, false if not.
31
32
  #
32
33
  # @since 2.0.0.rc.1
33
- def reject?(attrs)
34
- criteria = options[:reject_if]
35
- criteria ? criteria.call(attrs) : false
34
+ def reject?(document, attrs)
35
+ case callback = options[:reject_if]
36
+ when Symbol
37
+ document.method(callback).arity == 0 ? document.send(callback) : document.send(callback, attrs)
38
+ when Proc
39
+ callback.call(attrs)
40
+ else
41
+ false
42
+ end
36
43
  end
37
44
 
38
45
  # Determines if only updates can occur. Only valid for one-to-one
@@ -329,7 +329,7 @@ module Mongoid #:nodoc:
329
329
  # @example Get the value.
330
330
  # relation.convertable
331
331
  #
332
- # @return [ String, Unconvertable, BSON::ObjectId ] The string or object id.
332
+ # @return [ String, BSON::ObjectId ] The string or object id.
333
333
  #
334
334
  # @since 2.0.2
335
335
  def convertable
@@ -337,7 +337,9 @@ module Mongoid #:nodoc:
337
337
  if inverse.using_object_ids? || base.id.is_a?(BSON::ObjectId)
338
338
  base.id
339
339
  else
340
- Criterion::Unconvertable.new(base.id)
340
+ base.id.tap do |id|
341
+ id.unconvertable_to_bson = true if id.is_a?(String)
342
+ end
341
343
  end
342
344
  end
343
345
 
@@ -35,6 +35,7 @@ module Mongoid # :nodoc:
35
35
  doc.save
36
36
  else
37
37
  base.send(metadata.foreign_key).push(doc.id)
38
+ base.synced[metadata.foreign_key] = false
38
39
  end
39
40
  end
40
41
  if persistable? || creating?
@@ -142,7 +143,7 @@ module Mongoid # :nodoc:
142
143
  # @since 2.0.0.rc.1
143
144
  def nullify
144
145
  criteria.pull(metadata.inverse_foreign_key, base.id)
145
- unless base.destroyed?
146
+ if persistable?
146
147
  base.set(
147
148
  metadata.foreign_key,
148
149
  base.send(metadata.foreign_key).clear