mongoid 2.4.9 → 2.4.10

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.
@@ -3,10 +3,37 @@
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.10 (branch: 2.4.0-stable)
6
+ ## 2.4.11 (branch: 2.4.0-stable)
7
7
 
8
8
  ### Resolved Issues
9
9
 
10
+ ## 2.4.10
11
+
12
+ ### Resolved Issues
13
+
14
+ * \#2003 Don't fail on document generation when an embedded document was
15
+ stored as nil in the database.
16
+
17
+ * \#1997 Don't delete paranoid embedded docs via nested attributes when
18
+ a before_destroy callback returns false.
19
+
20
+ * \#1994 `dependent: :delete` only hits the database once now for one to
21
+ many and many to many relations instead of once for each document.
22
+
23
+ * \#1987 Don't double-insert documents into identity map when eager loading
24
+ twice inside the unit of work.
25
+
26
+ * \#1976 Don't execute eager load queries when base query is empty.
27
+
28
+ * \#1953 Uniqueness validation now works on localized fields.
29
+
30
+ * \#1936 Allow setting n levels deep embedded documents atomically without
31
+ conflicting mods when not using nested attributes or documents themselves
32
+ in an update call from the parent.
33
+
34
+ * \#1957/\#1954 Ensure database name is set with inheritance.
35
+ (Hans Hasselberg)
36
+
10
37
  ## 2.4.9
11
38
 
12
39
  ### Resolved Issues
@@ -252,6 +252,9 @@ module Mongoid #:nodoc:
252
252
  # @example Get the atomic paths.
253
253
  # document.atomic_paths
254
254
  #
255
+ # @todo: Durran: Should probably raise error for embedded docs w/o
256
+ # metadata.
257
+ #
255
258
  # @return [ Object ] The associated path.
256
259
  #
257
260
  # @since 2.1.0
@@ -144,13 +144,15 @@ module Mongoid #:nodoc:
144
144
  #
145
145
  # @since 2.4.1
146
146
  def eager_load(docs)
147
- parent_ids = docs.map(&:id)
148
147
  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)
148
+ unless docs.empty?
149
+ parent_ids = docs.map(&:id)
150
+ if metadata.macro == :referenced_in
151
+ child_ids = load_ids(metadata.foreign_key)
152
+ metadata.eager_load(child_ids)
153
+ else
154
+ metadata.eager_load(parent_ids)
155
+ end
154
156
  end
155
157
  end
156
158
  end
@@ -15,7 +15,7 @@ module Mongoid #:nodoc:
15
15
  # @param [ Hash ] optiosn The mass assignment scoping options.
16
16
  #
17
17
  # @return [ Document ] The instantiated document.
18
- def build(klass, attributes = {}, options = {})
18
+ def build(klass, attributes = nil, options = {})
19
19
  type = (attributes || {})["_type"]
20
20
  if type && klass._types.include?(type)
21
21
  type.constantize.new(attributes, options)
@@ -34,8 +34,8 @@ module Mongoid #:nodoc:
34
34
  # @param [ Hash ] attributes The document attributes.
35
35
  #
36
36
  # @return [ Document ] The instantiated document.
37
- def from_db(klass, attributes = {})
38
- type = attributes["_type"]
37
+ def from_db(klass, attributes = nil)
38
+ type = (attributes || {})["_type"]
39
39
  if type.blank?
40
40
  klass.instantiate(attributes)
41
41
  else
@@ -4,6 +4,21 @@ module Mongoid #:nodoc:
4
4
  # Defines behaviour for the identity map in Mongoid.
5
5
  class IdentityMap < Hash
6
6
 
7
+ # Clear the many documents.
8
+ #
9
+ # @example Clear the docs.
10
+ # identity_map.clear_many(Post, selector)
11
+ #
12
+ # @param [ Class ] klass The klass to clear.
13
+ # @param [ Hash ] selector The selector to identify it.
14
+ #
15
+ # @return [ Array<Document> ] The documents.
16
+ #
17
+ # @since 2.4.10
18
+ def clear_many(klass, selector)
19
+ (documents_for(klass)[selector] ||= []).clear
20
+ end
21
+
7
22
  # Get a document from the identity map by its id.
8
23
  #
9
24
  # @example Get the document from the map.
@@ -26,6 +26,11 @@ module Mongoid #:nodoc:
26
26
  def set_database(name)
27
27
  @database = name.to_s
28
28
  end
29
+
30
+ def inherited(subclass)
31
+ super
32
+ subclass.set_database(database.dup) if database
33
+ end
29
34
  end
30
35
  end
31
36
  end
@@ -27,8 +27,18 @@ module Mongoid # :nodoc:
27
27
  #
28
28
  # @example Perform the cascading delete.
29
29
  # strategy.cascade
30
+ #
31
+ # @since 2.0.0
30
32
  def cascade
31
- Array.wrap(relation).each { |doc| doc.delete } if relation
33
+ if relation
34
+ if relation.cascades.empty?
35
+ safety = Threaded.safety_options
36
+ relation.clear
37
+ Threaded.safety_options = safety
38
+ else
39
+ ::Array.wrap(relation).each { |doc| doc.delete }
40
+ end
41
+ end
32
42
  end
33
43
  end
34
44
  end
@@ -189,8 +189,12 @@ module Mongoid # :nodoc:
189
189
  target.delete_one(document).tap do |doc|
190
190
  _unscoped.delete_one(doc)
191
191
  if doc && !_binding?
192
- if _assigning? && !doc.paranoid?
193
- base.add_atomic_pull(doc)
192
+ if _assigning?
193
+ if doc.paranoid?
194
+ doc.destroy(:suppress => true)
195
+ else
196
+ base.add_atomic_pull(doc)
197
+ end
194
198
  else
195
199
  doc.delete(:suppress => true)
196
200
  end
@@ -307,7 +311,11 @@ module Mongoid # :nodoc:
307
311
  atomically(:$set) do
308
312
  base.delayed_atomic_sets.clear
309
313
  if replacement.first.is_a?(Hash)
310
- replacement = Many.builder(base, metadata, replacement).build
314
+ replacement = replacement.map do |doc|
315
+ attributes = { :metadata => metadata, :_parent => base }
316
+ attributes.merge!(doc)
317
+ Factory.build(klass, attributes)
318
+ end
311
319
  end
312
320
  docs = replacement.compact
313
321
  proxy.target = docs
@@ -319,6 +327,10 @@ module Mongoid # :nodoc:
319
327
  end
320
328
  if _assigning?
321
329
  name = _unscoped.first.atomic_path
330
+ base._children.each do |child|
331
+ child.delayed_atomic_sets.clear
332
+ end
333
+ base.instance_variable_set(:@_children, nil)
322
334
  base.delayed_atomic_sets[name] = proxy.as_document
323
335
  end
324
336
  end
@@ -6,6 +6,18 @@ module Mongoid # :nodoc:
6
6
  # behaviour or those proxies.
7
7
  class One < Proxy
8
8
 
9
+ # Clear this relation - same as calling #delete on the document.
10
+ #
11
+ # @example Clear the relation.
12
+ # relation.clear
13
+ #
14
+ # @return [ true, false ] If the delete suceeded.
15
+ #
16
+ # @since 3.0.0
17
+ def clear
18
+ target.delete
19
+ end
20
+
9
21
  # Get all the documents in the relation that are loaded into memory.
10
22
  #
11
23
  # @example Get the in memory documents.
@@ -563,9 +563,15 @@ module Mongoid #:nodoc:
563
563
  #
564
564
  # @since 2.2.0
565
565
  def eager_load(metadata, ids)
566
+ cleared = false
566
567
  klass, foreign_key = metadata.klass, metadata.foreign_key
567
568
  klass.any_in(foreign_key => ids).each do |doc|
568
- IdentityMap.set_many(doc, foreign_key => doc.send(foreign_key))
569
+ base_id = doc.send(foreign_key)
570
+ unless cleared
571
+ IdentityMap.clear_many(klass, foreign_key => base_id)
572
+ cleared = true
573
+ end
574
+ IdentityMap.set_many(doc, foreign_key => base_id)
569
575
  end
570
576
  end
571
577
 
@@ -141,6 +141,40 @@ module Mongoid #:nodoc:
141
141
  validates_with(UniquenessValidator, _merge_attributes(args))
142
142
  end
143
143
 
144
+ # Validates the format of a field.
145
+ #
146
+ # @example
147
+ # class Person
148
+ # include Mongoid::Document
149
+ # field :title
150
+ #
151
+ # validates_format_of :title, with: /^[a-z0-9 \-_]*$/i
152
+ # end
153
+ #
154
+ # @param [ Array ] args The names of the fields to validate.
155
+ #
156
+ # @since 2.4.0
157
+ def validates_format_of(*args)
158
+ validates_with(Mongoid::Validations::FormatValidator, _merge_attributes(args))
159
+ end
160
+
161
+ # Validates the length of a field.
162
+ #
163
+ # @example
164
+ # class Person
165
+ # include Mongoid::Document
166
+ # field :title
167
+ #
168
+ # validates_length_of :title, minimum: 100
169
+ # end
170
+ #
171
+ # @param [ Array ] args The names of the fields to validate.
172
+ #
173
+ # @since 2.4.0
174
+ def validates_length_of(*args)
175
+ validates_with(Mongoid::Validations::LengthValidator, _merge_attributes(args))
176
+ end
177
+
144
178
  # Validates whether or not a field is present - meaning nil or empty.
145
179
  #
146
180
  # @example
@@ -44,32 +44,36 @@ module Mongoid #:nodoc:
44
44
  attrib, val = to_validate(document, attribute, value)
45
45
  return unless validation_required?(document, attrib)
46
46
  if document.embedded?
47
- return if skip_validation?(document)
48
- relation = document._parent.send(document.metadata.name)
49
- criteria = relation.where(criterion(document, attrib, val))
50
- criteria = scope(criteria, document, attrib)
51
- if criteria.count > 1
52
- document.errors.add(
53
- attrib,
54
- :taken,
55
- options.except(:case_sensitive, :scope).merge(:val => val)
56
- )
57
- end
47
+ validate_embedded(document, attrib, val)
58
48
  else
59
- criteria = klass.unscoped.where(criterion(document, attrib, val))
60
- criteria = scope(criteria, document, attrib)
61
- if criteria.exists?
62
- document.errors.add(
63
- attrib, :taken, options.except(:case_sensitive, :scope).merge(:val => val)
64
- )
65
- end
49
+ validate_root(document, attrib, val)
66
50
  end
67
51
  end
68
52
 
69
- protected
53
+ private
54
+
55
+ # Add the error to the document.
56
+ #
57
+ # @api private
58
+ #
59
+ # @example Add the error.
60
+ # validator.add_error(doc, :name, "test")
61
+ #
62
+ # @param [ Document ] document The document to validate.
63
+ # @param [ Symbol ] attribute The name of the attribute.
64
+ # @param [ Object ] value The value of the object.
65
+ #
66
+ # @since 2.4.10
67
+ def add_error(document, attribute, value)
68
+ document.errors.add(
69
+ attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value)
70
+ )
71
+ end
70
72
 
71
73
  # Should the uniqueness validation be case sensitive?
72
74
  #
75
+ # @api private
76
+ #
73
77
  # @example Is the validation case sensitive?
74
78
  # validator.case_sensitive?
75
79
  #
@@ -80,8 +84,38 @@ module Mongoid #:nodoc:
80
84
  !(options[:case_sensitive] == false)
81
85
  end
82
86
 
87
+ # Create the validation criteria.
88
+ #
89
+ # @api private
90
+ #
91
+ # @example Create the criteria.
92
+ # validator.create_criteria(User, user, :name, "syd")
93
+ #
94
+ # @param [ Class, Proxy ] base The base to execute the criteria from.
95
+ # @param [ Document ] document The document to validate.
96
+ # @param [ Symbol ] attribute The name of the attribute.
97
+ # @param [ Object ] value The value of the object.
98
+ #
99
+ # @return [ Criteria ] The criteria.
100
+ #
101
+ # @since 2.4.10
102
+ def create_criteria(base, document, attribute, value)
103
+ field = document.fields[attribute.to_s]
104
+ criteria = base.unscoped
105
+ if field.try(:localized?)
106
+ criterion(document, attribute, value).each_pair do |key, value|
107
+ criteria.selector.store(key, value)
108
+ end
109
+ else
110
+ criteria = criteria.where(criterion(document, attribute, value))
111
+ end
112
+ scope(criteria, document, attribute)
113
+ end
114
+
83
115
  # Get the default criteria for checking uniqueness.
84
116
  #
117
+ # @api private
118
+ #
85
119
  # @example Get the criteria.
86
120
  # validator.criterion(person, :title, "Sir")
87
121
  #
@@ -102,6 +136,8 @@ module Mongoid #:nodoc:
102
136
 
103
137
  # Filter the value based on whether the check is case sensitive or not.
104
138
  #
139
+ # @api private
140
+ #
105
141
  # @example Filter the value.
106
142
  # validator.filter("testing")
107
143
  #
@@ -116,6 +152,8 @@ module Mongoid #:nodoc:
116
152
 
117
153
  # Scope the criteria to the scope options provided.
118
154
  #
155
+ # @api private
156
+ #
119
157
  # @example Scope the criteria.
120
158
  # validator.scope(criteria, document)
121
159
  #
@@ -134,6 +172,8 @@ module Mongoid #:nodoc:
134
172
 
135
173
  # Should validation be skipped?
136
174
  #
175
+ # @api private
176
+ #
137
177
  # @example Should the validation be skipped?
138
178
  # validator.skip_validation?(doc)
139
179
  #
@@ -148,6 +188,8 @@ module Mongoid #:nodoc:
148
188
 
149
189
  # Scope reference has changed?
150
190
  #
191
+ # @api private
192
+ #
151
193
  # @example Has scope reference changed?
152
194
  # validator.scope_value_changed?(doc)
153
195
  #
@@ -167,6 +209,8 @@ module Mongoid #:nodoc:
167
209
  # we need to send the key name and value to the db, not the relation
168
210
  # object.
169
211
  #
212
+ # @api private
213
+ #
170
214
  # @example Get the name and key to validate.
171
215
  # validator.to_validate(doc, :parent, Parent.new)
172
216
  #
@@ -186,6 +230,42 @@ module Mongoid #:nodoc:
186
230
  end
187
231
  end
188
232
 
233
+ # Validate an embedded document.
234
+ #
235
+ # @api private
236
+ #
237
+ # @example Validate the embedded document.
238
+ # validator.validate_embedded(doc, :name, "test")
239
+ #
240
+ # @param [ Document ] document The document.
241
+ # @param [ Symbol ] attribute The attribute name.
242
+ # @param [ Object ] value The value.
243
+ #
244
+ # @since 2.4.10
245
+ def validate_embedded(document, attribute, value)
246
+ return if skip_validation?(document)
247
+ relation = document._parent.send(document.metadata.name)
248
+ criteria = create_criteria(relation, document, attribute, value)
249
+ add_error(document, attribute, value) if criteria.count > 1
250
+ end
251
+
252
+ # Validate a root document.
253
+ #
254
+ # @api private
255
+ #
256
+ # @example Validate the root document.
257
+ # validator.validate_root(doc, :name, "test")
258
+ #
259
+ # @param [ Document ] document The document.
260
+ # @param [ Symbol ] attribute The attribute name.
261
+ # @param [ Object ] value The value.
262
+ #
263
+ # @since 2.4.10
264
+ def validate_root(document, attribute, value)
265
+ criteria = create_criteria(klass, document, attribute, value)
266
+ add_error(document, attribute, value) if criteria.exists?
267
+ end
268
+
189
269
  # Are we required to validate the document?
190
270
  #
191
271
  # @example Is validation needed?
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- VERSION = "2.4.9"
3
+ VERSION = "2.4.10"
4
4
  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.9
4
+ version: 2.4.10
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-24 00:00:00.000000000 Z
12
+ date: 2012-05-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -461,7 +461,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
461
461
  version: '0'
462
462
  segments:
463
463
  - 0
464
- hash: 3721994237204070315
464
+ hash: 2758014138080710719
465
465
  required_rubygems_version: !ruby/object:Gem::Requirement
466
466
  none: false
467
467
  requirements:
@@ -470,7 +470,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
470
470
  version: 1.3.6
471
471
  requirements: []
472
472
  rubyforge_project: mongoid
473
- rubygems_version: 1.8.19
473
+ rubygems_version: 1.8.24
474
474
  signing_key:
475
475
  specification_version: 3
476
476
  summary: Elegant Persistance in Ruby for MongoDB.