mongoid 2.3.3 → 2.3.4

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.
@@ -8,7 +8,55 @@ For instructions on upgrading to newer versions, visit
8
8
  * Ranges can now be passed to #where criteria to create a $gte/$lte query under the
9
9
  covers. `Person.where(dob: start_date...end_date)`
10
10
 
11
- ## 2.3.3 \[ In Development \] \[ Branch: 2.3.0-stable \]
11
+ ## 2.3.4 \[ In Development \] \[ Branch: 2.3.0-stable \]
12
+
13
+ * \#1445 Prevent duplicate documents in the loaded array on the target
14
+ enumerable for relational associations.
15
+
16
+ * \#1442 When using create_ methods for has one relations, the appropriate
17
+ destructive methods now get called when replacing an existing document.
18
+
19
+ * \#1431 Enumerable context should add to the loaded array post yield, so
20
+ that methods like #any? that short circuit based on the value of the block
21
+ dont falsely have extra documents.
22
+
23
+ * \#1418 Documents being loaded from the database for revision purposes
24
+ no longer get placed in the identity map.
25
+
26
+ * \#1399 Allow conversion of strings to integers in foreign keys where the
27
+ id is defined as an int.
28
+
29
+ * \#1397 Don't add default sorting criteria on first if they sort criteria
30
+ already exists.
31
+
32
+ * \#1394 Fix exists? to work when count is greater than 1. (Nick Hoffman)
33
+
34
+ * \#1392 Return 0 on aggregation functions where field is nonexistant.
35
+
36
+ * \#1391 Uniqueness validation now works properly on embedded documents that are
37
+ using primary key definitions.
38
+
39
+ * \#1390 When _type field is lower case class camelize before constantizing.
40
+
41
+ * \#1383 Fix cast on read for serializable fields that are subclassed.
42
+
43
+ * \#1357 Delayed atomic sets from update_attributes on embedded documents
44
+ multiple levels deep now properly persist.
45
+
46
+ * \#1326 Ensure base document on HABTM gets its keys saved after saving a newly
47
+ build child document.
48
+
49
+ * \#1301 Don't overwrite base metadata on embedded in relations if already set.
50
+
51
+ * \#1221 HABTM with inverse nil is allowed again on embedded documents.
52
+
53
+ * \#1208 Don't auto-persist child documents via the setter when setting from
54
+ an embedded_in.
55
+
56
+ * \#791 Root document updates its timestamps when only embedded documents have
57
+ changed.
58
+
59
+ ## 2.3.3
12
60
 
13
61
  ### Resolved Issues
14
62
 
@@ -5,22 +5,21 @@ id:
5
5
  taken:
6
6
  telah digunakan
7
7
  callbacks:
8
- "Calling %{method} on %{klass} resulted in a false return from a callback."
8
+ "Memanggil %{method} dalam %{klass} me-return false return dari salah satu callback."
9
9
  document_not_found:
10
10
  Dokumen tidak ditemukan untuk kelas %{klass} dengan id %{identifiers}.
11
11
  eager_load:
12
- "Eager loading :%{name} is not supported due to it being a many-to-many
13
- or polymorphic belongs_to relation."
12
+ "Eager loading : %{name} is tidak di-support karena merupakan relasi many-to-many
13
+ atau polymorphic belongs_to."
14
14
  invalid_time:
15
- "'%{value}' is not a valid Time."
15
+ "'%{value}' bukan merupakan Time yang valid."
16
16
  invalid_database:
17
17
  Database harus Mongo::DB, bukan %{name}.
18
18
  invalid_type:
19
19
  Field didefinisikan sebagai %{klass}, tetapi menerima %{other} dengan
20
20
  value %{value}.
21
21
  invalid_options:
22
- "Invalid option :%{invalid} provided to relation :%{name}. Valid options
23
- are: %{valid}."
22
+ "Opsi invalid : %{invalid} untuk relasi : %{name}. Opsi yang valid adalah : %{valid}."
24
23
  unsupported_version:
25
24
  MongoDB %{version} tidak di support, silakan upgrade
26
25
  ke %{mongo_version}.
@@ -242,7 +242,7 @@ module Mongoid #:nodoc:
242
242
  #
243
243
  # @return [ Numeric ] A numeric max value.
244
244
  def max(field)
245
- grouped(:max, field.to_s, Javascript.max)
245
+ grouped(:max, field.to_s, Javascript.max, Javascript.max_finalize)
246
246
  end
247
247
 
248
248
  # Return the min value for a field.
@@ -259,7 +259,7 @@ module Mongoid #:nodoc:
259
259
  #
260
260
  # @return [ Numeric ] A numeric minimum value.
261
261
  def min(field)
262
- grouped(:min, field.to_s, Javascript.min)
262
+ grouped(:min, field.to_s, Javascript.min, Javascript.min_finalize)
263
263
  end
264
264
 
265
265
  # Perform a pull on the matching documents.
@@ -306,7 +306,7 @@ module Mongoid #:nodoc:
306
306
  #
307
307
  # @return [ Numeric ] A numeric value that is the sum.
308
308
  def sum(field)
309
- grouped(:sum, field.to_s, Javascript.sum)
309
+ grouped(:sum, field.to_s, Javascript.sum, Javascript.sum_finalize)
310
310
  end
311
311
 
312
312
  # Very basic update that will perform a simple atomic $set of the
@@ -359,14 +359,14 @@ module Mongoid #:nodoc:
359
359
  # @param [ String ] reduce The reduce JS function.
360
360
  #
361
361
  # @return [ Numeric ] A numeric result.
362
- def grouped(start, field, reduce)
362
+ def grouped(start, field, reduce, finalize)
363
363
  collection = klass.collection.group(
364
364
  :cond => selector,
365
365
  :initial => { start => "start" },
366
+ :finalize => finalize,
366
367
  :reduce => reduce.gsub("[field]", field)
367
368
  )
368
- value = collection.empty? ? nil : collection.first[start.to_s]
369
- value && value.do_or_do_not(:nan?) ? nil : value
369
+ collection.empty? ? nil : collection.first[start.to_s]
370
370
  end
371
371
 
372
372
  # Get the options hash with the default sorting options provided.
@@ -379,9 +379,9 @@ module Mongoid #:nodoc:
379
379
  # @since 2.3.2
380
380
  def options_with_default_sorting
381
381
  process_options.tap do |opts|
382
- sorting = opts[:sort] ? opts[:sort].dup : []
383
- sorting << [:_id, :asc]
384
- opts[:sort] = sorting
382
+ if opts[:sort].blank?
383
+ opts[:sort] = [[ :_id, :asc ]]
384
+ end
385
385
  end
386
386
  end
387
387
 
@@ -242,7 +242,7 @@ module Mongoid #:nodoc:
242
242
  allocate.tap do |doc|
243
243
  doc.instance_variable_set(:@attributes, attributes)
244
244
  doc.send(:apply_defaults)
245
- IdentityMap.set(doc)
245
+ IdentityMap.set(doc) unless _loading_revision?
246
246
  doc.run_callbacks(:initialize) { doc }
247
247
  end
248
248
  end
@@ -22,7 +22,7 @@ module Mongoid #:nodoc:
22
22
  # BSON::ObjectId.convert(Person, { :_id => "4c52c439931a90ab29000003" })
23
23
  #
24
24
  # @param [ Class ] klass The class to convert the ids for.
25
- # @param [ Object, Array, Hash ] args The object to convert.
25
+ # @param [ Object, Array, Hash ] object The object to convert.
26
26
  #
27
27
  # @raise BSON::InvalidObjectId If using object ids and passed bad
28
28
  # strings.
@@ -30,28 +30,28 @@ module Mongoid #:nodoc:
30
30
  # @return [ BSON::ObjectId, Array, Hash ] The converted object ids.
31
31
  #
32
32
  # @since 2.0.0.rc.7
33
- def convert(klass, args, reject_blank = true)
34
- return args if args.is_a?(BSON::ObjectId) || !klass.using_object_ids?
35
- case args
33
+ def convert(klass, object, reject_blank = true)
34
+ return object if object.is_a?(BSON::ObjectId) || !klass.using_object_ids?
35
+ case object
36
36
  when ::String
37
- return nil if args.blank?
38
- if args.unconvertable_to_bson?
39
- args
37
+ return nil if object.blank?
38
+ if object.unconvertable_to_bson?
39
+ object
40
40
  else
41
- BSON::ObjectId.legal?(args) ? BSON::ObjectId.from_string(args) : args
41
+ BSON::ObjectId.legal?(object) ? BSON::ObjectId.from_string(object) : object
42
42
  end
43
43
  when ::Array
44
- args.delete_if { |arg| arg.blank? } if reject_blank
45
- args.replace(args.map { |arg| convert(klass, arg, reject_blank) })
44
+ object.delete_if { |arg| arg.blank? } if reject_blank
45
+ object.replace(object.map { |arg| convert(klass, arg, reject_blank) })
46
46
  when ::Hash
47
- args.tap do |hash|
47
+ object.tap do |hash|
48
48
  hash.each_pair do |key, value|
49
49
  next unless klass.object_id_field?(key)
50
50
  hash[key] = convert(klass, value, reject_blank)
51
51
  end
52
52
  end
53
53
  else
54
- args
54
+ object
55
55
  end
56
56
  end
57
57
  end
@@ -36,7 +36,11 @@ module Mongoid #:nodoc:
36
36
  # @return [ Document ] The instantiated document.
37
37
  def from_db(klass, attributes = {})
38
38
  type = attributes["_type"]
39
- type.blank? ? klass.instantiate(attributes) : type.constantize.instantiate(attributes)
39
+ if type.blank?
40
+ klass.instantiate(attributes)
41
+ else
42
+ type.camelize.constantize.instantiate(attributes)
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -30,28 +30,13 @@ module Mongoid #:nodoc:
30
30
  unless method_defined?(:default)
31
31
  alias :default :default_val
32
32
  end
33
+
34
+ class_attribute :cast_on_read
33
35
  end
34
36
 
35
37
  # Set readers for the instance variables.
36
38
  attr_accessor :default_val, :label, :localize, :name, :options
37
39
 
38
- # When reading the field do we need to cast the value? This holds true when
39
- # times are stored or for big decimals which are stored as strings.
40
- #
41
- # @example Typecast on a read?
42
- # field.cast_on_read?
43
- #
44
- # @return [ true, false ] If the field should be cast.
45
- #
46
- # @since 2.1.0
47
- def cast_on_read?
48
- return @cast_on_read if defined?(@cast_on_read)
49
- @cast_on_read =
50
- self.class.public_instance_methods(false).map do |m|
51
- m.to_sym
52
- end.include?(:deserialize)
53
- end
54
-
55
40
  # Get the constraint from the metadata once.
56
41
  #
57
42
  # @example Get the constraint.
@@ -195,6 +180,21 @@ module Mongoid #:nodoc:
195
180
  end
196
181
  end
197
182
  end
183
+
184
+ private
185
+
186
+ # If we define a method called deserialize then we need to cast on
187
+ # read.
188
+ #
189
+ # @example Hook into method added.
190
+ # method_added(:deserialize)
191
+ #
192
+ # @param [ Symbol ] method The method name.
193
+ #
194
+ # @since 2.3.4
195
+ def method_added(method)
196
+ self.cast_on_read = true if method == :deserialize
197
+ end
198
198
  end
199
199
  end
200
200
  end
@@ -33,7 +33,12 @@ module Mongoid #:nodoc:
33
33
  #
34
34
  # @since 2.1.0
35
35
  def serialize(object)
36
- object.blank? ? nil : constraint.convert(object)
36
+ return nil if object.blank?
37
+ if object_id_field?
38
+ constraint.convert(object)
39
+ else
40
+ metadata.klass.fields["_id"].serialize(object)
41
+ end
37
42
  end
38
43
  end
39
44
  end
@@ -6,6 +6,17 @@ module Mongoid #:nodoc:
6
6
  class Time
7
7
  include Serializable
8
8
  include Timekeeping
9
+
10
+ # When reading the field do we need to cast the value? This holds true when
11
+ # times are stored or for big decimals which are stored as strings.
12
+ #
13
+ # @example Typecast on a read?
14
+ # field.cast_on_read?
15
+ #
16
+ # @return [ true ] Date fields cast on read.
17
+ #
18
+ # @since 2.1.0
19
+ def cast_on_read?; true; end
9
20
  end
10
21
  end
11
22
  end
@@ -6,6 +6,17 @@ module Mongoid #:nodoc:
6
6
  class TimeWithZone
7
7
  include Serializable
8
8
  include Timekeeping
9
+
10
+ # When reading the field do we need to cast the value? This holds true when
11
+ # times are stored or for big decimals which are stored as strings.
12
+ #
13
+ # @example Typecast on a read?
14
+ # field.cast_on_read?
15
+ #
16
+ # @return [ true ] Date fields cast on read.
17
+ #
18
+ # @since 2.1.0
19
+ def cast_on_read?; true; end
9
20
  end
10
21
  end
11
22
  end
@@ -57,7 +57,7 @@ module Mongoid #:nodoc:
57
57
  #
58
58
  # @param [ Array ] args The conditions.
59
59
  def exists?(*args)
60
- find(:all, *args).limit(1).count == 1
60
+ find(:all, *args).count > 0
61
61
  end
62
62
 
63
63
  # Find a +Document+ in several different ways.
@@ -18,6 +18,14 @@ max:
18
18
  }
19
19
  }"
20
20
 
21
+ max_finalize:
22
+ "function(obj) {
23
+ if (obj.max == 'start' || isNaN(obj.max)) {
24
+ obj.max = 0;
25
+ }
26
+ return obj;
27
+ }"
28
+
21
29
  min:
22
30
  "function(obj, prev) {
23
31
  if (obj.[field] && prev.min == 'start') {
@@ -28,6 +36,14 @@ min:
28
36
  }
29
37
  }"
30
38
 
39
+ min_finalize:
40
+ "function(obj) {
41
+ if (obj.min == 'start' || isNaN(obj.min)) {
42
+ obj.min = 0;
43
+ }
44
+ return obj;
45
+ }"
46
+
31
47
  sum:
32
48
  "function(obj, prev) {
33
49
  if (prev.sum == 'start') {
@@ -37,3 +53,11 @@ sum:
37
53
  prev.sum += obj.[field];
38
54
  }
39
55
  }"
56
+
57
+ sum_finalize:
58
+ "function(obj) {
59
+ if (obj.sum == 'start' || isNaN(obj.sum)) {
60
+ obj.sum = 0;
61
+ }
62
+ return obj;
63
+ }"
@@ -42,6 +42,15 @@ 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
+
45
54
  collection.update(selector, updates, options)
46
55
  conflicts.each_pair do |key, value|
47
56
  collection.update(selector, { key => value }, options)
@@ -24,7 +24,7 @@ module Mongoid # :nodoc:
24
24
  #
25
25
  # @since 2.0.0.rc.1
26
26
  def bind
27
- base.metadata = metadata.inverse_metadata(target)
27
+ base.metadata = metadata.inverse_metadata(target) unless base.metadata
28
28
  base.parentize(target)
29
29
  unless _binding?
30
30
  _binding do
@@ -32,6 +32,23 @@ module Mongoid # :nodoc:
32
32
  module Builders
33
33
  extend ActiveSupport::Concern
34
34
 
35
+ private
36
+
37
+ # Parse out the attributes and the options from the args passed to a
38
+ # build_ or create_ methods.
39
+ #
40
+ # @example Parse the args.
41
+ # doc.parse_args(:name => "Joe")
42
+ #
43
+ # @param [ Array ] args The arguments.
44
+ #
45
+ # @return [ Array<Hash> ] The attributes and options.
46
+ #
47
+ # @since 2.3.4
48
+ def parse_args(*args)
49
+ [ args.first || {}, args.size > 1 ? args[1] : {} ]
50
+ end
51
+
35
52
  module ClassMethods #:nodoc:
36
53
 
37
54
  # Defines a builder method for an embeds_one relation. This is
@@ -48,8 +65,7 @@ module Mongoid # :nodoc:
48
65
  def builder(name, metadata)
49
66
  tap do
50
67
  define_method("build_#{name}") do |*args|
51
- attributes = args.first || {}
52
- options = args.size > 1 ? args[1] : {}
68
+ attributes, options = parse_args(*args)
53
69
  document = Factory.build(metadata.klass, attributes, options)
54
70
  _building do
55
71
  send("#{name}=", document)
@@ -70,10 +86,12 @@ module Mongoid # :nodoc:
70
86
  # @return [ Class ] The class being set up.
71
87
  #
72
88
  # @since 2.0.0.rc.1
73
- def creator(name)
89
+ def creator(name, metadata)
74
90
  tap do
75
91
  define_method("create_#{name}") do |*args|
76
- send("build_#{name}", *args).tap { |doc| doc.save }
92
+ attributes, options = parse_args(*args)
93
+ document = Factory.build(metadata.klass, attributes, options)
94
+ send("#{name}=", document).tap { |doc| doc.save }
77
95
  end
78
96
  end
79
97
  end
@@ -22,7 +22,6 @@ module Mongoid # :nodoc:
22
22
  init(base, target, metadata) do
23
23
  characterize_one(target)
24
24
  bind_one
25
- base.save if persistable?
26
25
  end
27
26
  end
28
27
 
@@ -103,7 +103,7 @@ module Mongoid # :nodoc:
103
103
  def embeds_one(name, options = {}, &block)
104
104
  characterize(name, Embedded::One, options, &block).tap do |meta|
105
105
  relate(name, meta)
106
- builder(name, meta).creator(name)
106
+ builder(name, meta).creator(name, meta)
107
107
  validates_relation(meta)
108
108
  end
109
109
  end
@@ -219,7 +219,7 @@ module Mongoid # :nodoc:
219
219
  characterize(name, Referenced::One, options, &block).tap do |meta|
220
220
  relate(name, meta)
221
221
  reference(meta)
222
- builder(name, meta).creator(name).autosave(meta)
222
+ builder(name, meta).creator(name, meta).autosave(meta)
223
223
  validates_relation(meta)
224
224
  end
225
225
  end
@@ -75,6 +75,7 @@ module Mongoid # :nodoc:
75
75
  Factory.build(type || klass, attributes, options).tap do |doc|
76
76
  base.send(metadata.foreign_key).push(doc.id)
77
77
  append(doc)
78
+ doc.synced[metadata.inverse_foreign_key] = false
78
79
  yield(doc) if block_given?
79
80
  end
80
81
  end
@@ -151,8 +151,8 @@ module Mongoid #:nodoc:
151
151
  end
152
152
  else
153
153
  unloaded.each do |doc|
154
- loaded.push(added.delete_one(doc) || doc)
155
154
  yield(doc)
155
+ loaded.push(added.delete_one(doc) || loaded.delete_one(doc) || doc)
156
156
  end
157
157
  end
158
158
  added.each do |doc|
@@ -67,7 +67,7 @@ module Mongoid #:nodoc:
67
67
  new? &&
68
68
  embedded_many? &&
69
69
  _parent.persisted? &&
70
- !_parent.delayed_atomic_sets[atomic_path]
70
+ !_parent.delayed_atomic_sets[metadata.name.to_s]
71
71
  end
72
72
 
73
73
  # Determine if the document can be set.
@@ -56,7 +56,7 @@ module Mongoid #:nodoc:
56
56
  create_stack.push(true)
57
57
  end
58
58
 
59
- # Begins a creating block.
59
+ # Begins a loading block.
60
60
  #
61
61
  # @example Begin the load.
62
62
  # Threaded.begin_load
@@ -68,6 +68,18 @@ module Mongoid #:nodoc:
68
68
  load_stack.push(true)
69
69
  end
70
70
 
71
+ # Begins a loading revision block.
72
+ #
73
+ # @example Begin the revision load.
74
+ # Threaded.begin_load_revision
75
+ #
76
+ # @return [ true ] Always true.
77
+ #
78
+ # @since 2.3.4
79
+ def begin_load_revision
80
+ load_revision_stack.push(true)
81
+ end
82
+
71
83
  # Begin validating a document on the current thread.
72
84
  #
73
85
  # @example Begin validation.
@@ -128,18 +140,30 @@ module Mongoid #:nodoc:
128
140
  !create_stack.empty?
129
141
  end
130
142
 
131
- # Is the current thread in creating mode?
143
+ # Is the current thread in loading mode?
132
144
  #
133
- # @example Is the thread in creating mode?
134
- # Threaded.creating?
145
+ # @example Is the thread in loading mode?
146
+ # Threaded.loading?
135
147
  #
136
- # @return [ true, false ] If the thread is in creating mode?
148
+ # @return [ true, false ] If the thread is in loading mode?
137
149
  #
138
150
  # @since 2.3.2
139
151
  def loading?
140
152
  !load_stack.empty?
141
153
  end
142
154
 
155
+ # Is the current thread in revision load mode?
156
+ #
157
+ # @example Is the thread in revision load mode?
158
+ # Threaded.loading_revision?
159
+ #
160
+ # @return [ true, false ] If the thread is in revision load mode?
161
+ #
162
+ # @since 2.3.4
163
+ def loading_revision?
164
+ !load_revision_stack.empty?
165
+ end
166
+
143
167
  # Get the assign stack for the current thread. Is simply an array of calls
144
168
  # to Mongoid's assigning method.
145
169
  #
@@ -205,6 +229,19 @@ module Mongoid #:nodoc:
205
229
  Thread.current[:"[mongoid]:load-stack"] ||= []
206
230
  end
207
231
 
232
+ # Get the revision load stack for the current thread. Is simply an array
233
+ # of calls to Mongoid's loading_revision method.
234
+ #
235
+ # @example Get the revision load stack.
236
+ # Threaded.load_revision_stack
237
+ #
238
+ # @return [ Array ] The array of load revision calls.
239
+ #
240
+ # @since 2.3.4
241
+ def load_revision_stack
242
+ Thread.current[:"[mongoid]:load-revision-stack"] ||= []
243
+ end
244
+
208
245
  # Clear out all the safety options set using the safely proxy.
209
246
  #
210
247
  # @example Clear out the options.
@@ -288,6 +325,18 @@ module Mongoid #:nodoc:
288
325
  load_stack.pop
289
326
  end
290
327
 
328
+ # Exit the revision loading block.
329
+ #
330
+ # @example Exit the revision loading block.
331
+ # Threaded.exit_load_revision
332
+ #
333
+ # @return [ true ] The last element in the stack.
334
+ #
335
+ # @since 2.3.4
336
+ def exit_load_revision
337
+ load_revision_stack.pop
338
+ end
339
+
291
340
  # Exit validating a document on the current thread.
292
341
  #
293
342
  # @example Exit validation.
@@ -139,6 +139,23 @@ module Mongoid #:nodoc:
139
139
  Threaded.loading?
140
140
  end
141
141
 
142
+ # Execute a block in loading revision mode.
143
+ #
144
+ # @example Execute in loading revision mode.
145
+ # _loading_revision do
146
+ # load_revision
147
+ # end
148
+ #
149
+ # @return [ Object ] The return value of the block.
150
+ #
151
+ # @since 2.3.4
152
+ def _loading_revision
153
+ Threaded.begin_load_revision
154
+ yield
155
+ ensure
156
+ Threaded.exit_load_revision
157
+ end
158
+
142
159
  module ClassMethods #:nodoc:
143
160
 
144
161
  # Execute a block in creating mode.
@@ -157,6 +174,18 @@ module Mongoid #:nodoc:
157
174
  ensure
158
175
  Threaded.exit_create
159
176
  end
177
+
178
+ # Is the current thread in loading revision mode?
179
+ #
180
+ # @example Is the current thread in loading revision mode?
181
+ # proxy._loading_revision?
182
+ #
183
+ # @return [ true, false ] If the thread is loading a revision.
184
+ #
185
+ # @since 2.3.4
186
+ def _loading_revision?
187
+ Threaded.loading_revision?
188
+ end
160
189
  end
161
190
  end
162
191
  end
@@ -19,7 +19,7 @@ module Mongoid #:nodoc:
19
19
  # @example Set the updated at time.
20
20
  # person.set_updated_at
21
21
  def set_updated_at
22
- self.updated_at = Time.now.utc unless self.updated_at_changed?
22
+ self.updated_at = Time.now.utc unless updated_at_changed?
23
23
  end
24
24
  end
25
25
  end
@@ -45,11 +45,17 @@ module Mongoid #:nodoc:
45
45
  return if skip_validation?(document)
46
46
  relation = document._parent.send(document.metadata.name)
47
47
  criteria = relation.where(criterion(document, attribute, value))
48
+ criteria = scope(criteria, document, attribute)
49
+ if document.primary_key == Array.wrap(attribute)
50
+ document.errors.add(attribute, :taken) if criteria.count > 1
51
+ else
52
+ document.errors.add(attribute, :taken) if criteria.exists?
53
+ end
48
54
  else
49
55
  criteria = klass.where(criterion(document, attribute, value))
56
+ criteria = scope(criteria, document, attribute)
57
+ document.errors.add(attribute, :taken) if criteria.exists?
50
58
  end
51
- criteria = scope(criteria, document, attribute)
52
- document.errors.add(attribute, :taken) if criteria.exists?
53
59
  end
54
60
 
55
61
  protected
@@ -80,7 +86,8 @@ module Mongoid #:nodoc:
80
86
  # @since 2.3.0
81
87
  def criterion(document, attribute, value)
82
88
  { attribute => filter(value) }.tap do |selector|
83
- if document.persisted? || document.embedded?
89
+ if document.persisted? ||
90
+ (document.embedded? && (document.primary_key != Array.wrap(attribute)))
84
91
  selector.merge!(:_id => { "$ne" => document.id })
85
92
  end
86
93
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- VERSION = "2.3.3"
3
+ VERSION = "2.3.4"
4
4
  end
@@ -117,9 +117,11 @@ module Mongoid #:nodoc:
117
117
  #
118
118
  # @since 2.0.0
119
119
  def previous_revision
120
- self.class.
121
- where(:_id => id).
122
- any_of({ :version => version }, { :version => nil }).first
120
+ _loading_revision do
121
+ self.class.
122
+ where(:_id => id).
123
+ any_of({ :version => version }, { :version => nil }).first
124
+ end
123
125
  end
124
126
 
125
127
  # Is the document able to be revised? This is true if the document has
@@ -16,13 +16,15 @@ module Rails #:nodoc:
16
16
  # @since 2.1.0
17
17
  def create_indexes(pattern)
18
18
  Dir.glob(pattern).each do |file|
19
+ logger = Logger.new($stdout)
19
20
  begin
20
21
  model = determine_model(file)
21
22
  if model
22
23
  model.create_indexes
23
- Logger.new($stdout).info("Generated indexes for #{model}")
24
+ logger.info("Generated indexes for #{model}")
24
25
  end
25
26
  rescue => e
27
+ logger.error("ERROR: #{e.message}")
26
28
  end
27
29
  end
28
30
  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.3.3
4
+ version: 2.3.4
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: 2011-10-31 00:00:00.000000000Z
12
+ date: 2011-11-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
16
- requirement: &70239778174840 !ruby/object:Gem::Requirement
16
+ requirement: &70174220762600 !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: *70239778174840
24
+ version_requirements: *70174220762600
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tzinfo
27
- requirement: &70239778174200 !ruby/object:Gem::Requirement
27
+ requirement: &70174220760140 !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: *70239778174200
35
+ version_requirements: *70174220760140
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: mongo
38
- requirement: &70239778173520 !ruby/object:Gem::Requirement
38
+ requirement: &70174220759060 !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: *70239778173520
46
+ version_requirements: *70174220759060
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rdoc
49
- requirement: &70239778172400 !ruby/object:Gem::Requirement
49
+ requirement: &70174220792380 !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: *70239778172400
57
+ version_requirements: *70174220792380
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bson_ext
60
- requirement: &70239778171440 !ruby/object:Gem::Requirement
60
+ requirement: &70174220788760 !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: *70239778171440
68
+ version_requirements: *70174220788760
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
- requirement: &70239778170600 !ruby/object:Gem::Requirement
71
+ requirement: &70174220786360 !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: *70239778170600
79
+ version_requirements: *70174220786360
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70239778169700 !ruby/object:Gem::Requirement
82
+ requirement: &70174220785700 !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: *70239778169700
90
+ version_requirements: *70174220785700
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: watchr
93
- requirement: &70239778168680 !ruby/object:Gem::Requirement
93
+ requirement: &70174220855580 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0.6'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70239778168680
101
+ version_requirements: *70174220855580
102
102
  description: Mongoid is an ODM (Object Document Mapper) Framework for MongoDB, written
103
103
  in Ruby.
104
104
  email:
@@ -393,7 +393,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
393
393
  version: '0'
394
394
  segments:
395
395
  - 0
396
- hash: 1966370546899582904
396
+ hash: 4304237674641660259
397
397
  required_rubygems_version: !ruby/object:Gem::Requirement
398
398
  none: false
399
399
  requirements:
@@ -402,7 +402,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
402
402
  version: 1.3.6
403
403
  requirements: []
404
404
  rubyforge_project: mongoid
405
- rubygems_version: 1.8.6
405
+ rubygems_version: 1.8.10
406
406
  signing_key:
407
407
  specification_version: 3
408
408
  summary: Elegant Persistance in Ruby for MongoDB.