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
@@ -2,14 +2,68 @@
2
2
 
3
3
  For instructions on upgrading to newer versions, visit [mongoid.org](http://mongoid.org/docs/upgrading.html).
4
4
 
5
+ ## 2.2.1
6
+
7
+ ### Resolved Issues
8
+
9
+ * \#1210, \#517 Allow embedded document relation queries to use dot notation.
10
+ (Scott Ellard)
11
+
12
+ * \#1198 Enumerable target should use criteria count if loaded has no docs.
13
+
14
+ * \#1164 Get rid of remaining no method in_memory errors.
15
+
16
+ * \#1070 Allow custom field serializers to have their own constructors.
17
+
18
+ * \#1176 Allow access to parent documents from embedded docs in after_destroy
19
+ callbacks.
20
+
21
+ * \#1191 Context group methods (min, max, sum) no longer return NaN but instead
22
+ return nil if field doesn't exist or have values.
23
+
24
+ * \#1193, \#1271 Always return Integers for integer fields with .000 precisions,
25
+ not floats.
26
+
27
+ * \#1199 Fixed performance issues of hash and array field access when reading
28
+ multiple times.
29
+
30
+ * \#1218 Fixed issues with relations referencing models with integer foreign keys.
31
+
32
+ * \#1219 Fixed various conflicting modifications issues when pushing and pulling
33
+ from the same embedded document in a single call.
34
+
35
+ * \#1220 Metadata should not get overwritten by nil on binding.
36
+
37
+ * \#1231 Renamed Mongoid's atomic set class to Sets to avoid conflicts with Ruby's
38
+ native Set after document inclusion.
39
+
40
+ * \#1232 Fix access to related models during before_destroy callbacks when
41
+ cascading.
42
+
43
+ * \#1234 Fixed HABTM foreign key synchronization issues when destroying
44
+ documents.
45
+
46
+ * \#1243 Polymorphic relations dont convert to object ids when querying if the
47
+ ids are defined as strings.
48
+
49
+ * \#1247 Force Model.first to sort by ascending id to guarantee first document.
50
+
51
+ * \#1248 Added #unscoped to embedded many relations.
52
+
53
+ * \#1249 Destroy flags in nested attributes now actually destroy the document
54
+ for has_many instead of just breaking the relation.
55
+
56
+ * \#1272 Don't modify configuration options in place when creating replica set
57
+ connections.
58
+
5
59
  ## 2.2.0
6
60
 
7
61
  ### New Features
8
62
 
9
- * Mongoid now contains eager loading in the form of `Criteria#includes(|*args)`.
10
- This works on all relational associations and requires the identity map to
63
+ * Mongoid now contains eager loading in the form of `Criteria#includes(*args)`.
64
+ This works on has_one, has_many, belongs_to associations and requires the identity map to
11
65
  be enabled in order to function. Set `identity_map_enabled: true` in your
12
- `mongoid.yml`.
66
+ `mongoid.yml`. Ex: `Person.where(title: "Sir").includes(:posts, :game)`
13
67
 
14
68
  * Relations can now take a module as a value to the `:extend` option. (Roman
15
69
  Shterenzon)
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ task :install => :build do
19
19
  end
20
20
 
21
21
  task :release => :build do
22
- system "git tag -a #{Mongoid::VERSION} -m 'Tagging #{Mongoid::VERSION}'"
22
+ system "git tag -a v#{Mongoid::VERSION} -m 'Tagging #{Mongoid::VERSION}'"
23
23
  system "git push --tags"
24
24
  system "gem push mongoid-#{Mongoid::VERSION}.gem"
25
25
  end
@@ -115,7 +115,8 @@ module Mongoid #:nodoc:
115
115
  #
116
116
  # @since 2.2.0
117
117
  def push_conflict?(field)
118
- set_fields.include?(field.split(".", 2)[0])
118
+ name = field.split(".", 2)[0]
119
+ set_fields.include?(name) || pull_fields.include?(name)
119
120
  end
120
121
 
121
122
  # Get the conflicting pull modifications.
@@ -48,7 +48,6 @@ module Mongoid #:nodoc
48
48
 
49
49
  option :allow_dynamic_fields, :default => true
50
50
  option :autocreate_indexes, :default => false
51
- option :binding_defaults, :default => { :binding => false, :continue => true }
52
51
  option :identity_map_enabled, :default => false
53
52
  option :include_root_in_json, :default => false
54
53
  option :max_retries_on_connection_failure, :default => 0
@@ -14,14 +14,14 @@ module Mongoid #:nodoc:
14
14
  #
15
15
  # @since 2.0.0.rc.5
16
16
  def configure
17
- # yes, construction is weird but the driver wants
17
+ # yes, construction is weird but the driver wants
18
18
  # "A list of host-port pairs ending with a hash containing any options"
19
19
  # mongo likes symbols
20
20
  options = self.inject({ :logger => Mongoid::Logger.new }) do |memo, (k, v)|
21
21
  memo[k.to_sym] = v
22
22
  memo
23
23
  end
24
- connection = Mongo::ReplSetConnection.new(*(hosts << options))
24
+ connection = Mongo::ReplSetConnection.new(*(hosts.clone << options))
25
25
 
26
26
  if authenticating?
27
27
  connection.add_auth(database, username, password)
@@ -4,7 +4,8 @@ module Mongoid #:nodoc:
4
4
  class Mongo
5
5
  attr_accessor :criteria
6
6
 
7
- delegate :klass, :options, :field_list, :selector, :to => :criteria
7
+ delegate :cached?, :klass, :options, :field_list, :selector, :to => :criteria
8
+ delegate :collection, :to => :klass
8
9
 
9
10
  # Perform an add to set on the matching documents.
10
11
  #
@@ -86,7 +87,11 @@ module Mongoid #:nodoc:
86
87
  #
87
88
  # @return [ Integer ] The count of documents.
88
89
  def count(extras = false)
89
- @count ||= klass.collection.find(selector, process_options).count(extras)
90
+ if cached?
91
+ @count ||= collection.find(selector, process_options).count(extras)
92
+ else
93
+ collection.find(selector, process_options).count(extras)
94
+ end
90
95
  end
91
96
  alias :size :count
92
97
  alias :length :count
@@ -153,7 +158,10 @@ module Mongoid #:nodoc:
153
158
  #
154
159
  # @return [ Document ] The first document in the collection.
155
160
  def first
156
- attributes = klass.collection.find_one(selector, process_options)
161
+ opts = process_options
162
+ sorting = opts[:sort] ||= []
163
+ sorting << [:_id, :asc]
164
+ attributes = klass.collection.find_one(selector, opts)
157
165
  attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
158
166
  end
159
167
  alias :one :first
@@ -202,7 +210,7 @@ module Mongoid #:nodoc:
202
210
  # @example Iterate over the results.
203
211
  # context.iterate { |doc| p doc }
204
212
  def iterate(&block)
205
- return caching(&block) if criteria.cached?
213
+ return caching(&block) if cached?
206
214
  if block_given?
207
215
  execute.each { |doc| yield doc }
208
216
  end
@@ -362,7 +370,8 @@ module Mongoid #:nodoc:
362
370
  :initial => { start => "start" },
363
371
  :reduce => reduce.gsub("[field]", field)
364
372
  )
365
- collection.empty? ? nil : collection.first[start.to_s]
373
+ value = collection.empty? ? nil : collection.first[start.to_s]
374
+ value ? (value.nan? ? nil : value) : value
366
375
  end
367
376
 
368
377
  # Filters the field list. If no fields have been supplied, then it will be
@@ -7,7 +7,6 @@ require "mongoid/criterion/inclusion"
7
7
  require "mongoid/criterion/inspection"
8
8
  require "mongoid/criterion/optional"
9
9
  require "mongoid/criterion/selector"
10
- require "mongoid/criterion/unconvertable"
11
10
 
12
11
  module Mongoid #:nodoc:
13
12
 
@@ -195,9 +194,10 @@ module Mongoid #:nodoc:
195
194
  @options, @klass, @documents, @embedded = {}, klass, [], embedded
196
195
  end
197
196
 
198
- # Merges another object into this +Criteria+. The other object may be a
199
- # +Criteria+ or a +Hash+. This is used to combine multiple scopes together,
200
- # where a chained scope situation may be desired.
197
+ # Merges another object with this +Criteria+ and returns a new criteria.
198
+ # The other object may be a +Criteria+ or a +Hash+. This is used to
199
+ # combine multiple scopes together, where a chained scope situation
200
+ # may be desired.
201
201
  #
202
202
  # @example Merge the criteria with a conditions hash.
203
203
  # criteria.merge({ :conditions => { :title => "Sir" } })
@@ -247,12 +247,27 @@ module Mongoid #:nodoc:
247
247
  #
248
248
  # @since 2.0.0
249
249
  def execute_or_raise(args, criteria)
250
- (args[0].is_a?(Array) ? criteria.entries : criteria.one).tap do |result|
250
+ (args[0].is_a?(Array) ? criteria.entries : from_map_or_db(criteria)).tap do |result|
251
251
  if Mongoid.raise_not_found_error && !args.flatten.blank?
252
252
  raise Errors::DocumentNotFound.new(klass, args) if result._vacant?
253
253
  end
254
254
  end
255
255
  end
256
+
257
+ # Get the document from the identity map, and if not found hit the
258
+ # database.
259
+ #
260
+ # @example Get the document from the map or criteria.
261
+ # criteria.from_map_or_db(criteria)
262
+ #
263
+ # @param [ Criteria ] The cloned criteria.
264
+ #
265
+ # @return [ Document ] The found document.
266
+ #
267
+ # @since 2.2.1
268
+ def from_map_or_db(criteria)
269
+ IdentityMap.get(klass, criteria.selector[:_id]) || criteria.one
270
+ end
256
271
  end
257
272
  end
258
273
  end
@@ -7,9 +7,7 @@ module Mongoid #:nodoc:
7
7
  extend ActiveSupport::Concern
8
8
  include Mongoid::Components
9
9
 
10
- included do
11
- attr_reader :new_record
12
- end
10
+ attr_reader :new_record
13
11
 
14
12
  # Default comparison is via the string version of the id.
15
13
  #
@@ -181,7 +179,7 @@ module Mongoid #:nodoc:
181
179
  attributes.tap do |attrs|
182
180
  relations.each_pair do |name, meta|
183
181
  if meta.embedded?
184
- relation = send(name, false, :continue => false)
182
+ relation = send(name)
185
183
  attrs[name] = relation.as_document unless relation.blank?
186
184
  end
187
185
  end
@@ -3,12 +3,14 @@ require "mongoid/extensions/array/deletion"
3
3
  require "mongoid/extensions/false_class/equality"
4
4
  require "mongoid/extensions/hash/criteria_helpers"
5
5
  require "mongoid/extensions/hash/scoping"
6
+ require "mongoid/extensions/integer/checks"
6
7
  require "mongoid/extensions/nil/collectionization"
7
8
  require "mongoid/extensions/object/checks"
8
9
  require "mongoid/extensions/object/reflections"
9
10
  require "mongoid/extensions/object/substitutable"
10
11
  require "mongoid/extensions/object/yoda"
11
12
  require "mongoid/extensions/proc/scoping"
13
+ require "mongoid/extensions/string/checks"
12
14
  require "mongoid/extensions/string/conversions"
13
15
  require "mongoid/extensions/string/inflections"
14
16
  require "mongoid/extensions/symbol/inflections"
@@ -33,6 +35,10 @@ class Hash #:nodoc
33
35
  include Mongoid::Extensions::Hash::Scoping
34
36
  end
35
37
 
38
+ class Integer #:nodoc
39
+ include Mongoid::Extensions::Integer::Checks
40
+ end
41
+
36
42
  class NilClass #:nodoc
37
43
  include Mongoid::Extensions::Nil::Collectionization
38
44
  end
@@ -49,6 +55,7 @@ class Proc #:nodoc:
49
55
  end
50
56
 
51
57
  class String #:nodoc
58
+ include Mongoid::Extensions::String::Checks
52
59
  include Mongoid::Extensions::String::Conversions
53
60
  include Mongoid::Extensions::String::Inflections
54
61
  end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Integer #:nodoc:
5
+
6
+ # This module has object checks in it.
7
+ module Checks #:nodoc:
8
+
9
+ # Is the object not to be converted to bson on criteria creation?
10
+ #
11
+ # @example Is the object unconvertable?
12
+ # object.unconvertable_to_bson?
13
+ #
14
+ # @return [ true ] If the object is unconvertable.
15
+ #
16
+ # @since 2.2.1
17
+ def unconvertable_to_bson?
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -21,6 +21,22 @@ module Mongoid #:nodoc:
21
21
  def do_or_do_not(name, *args)
22
22
  respond_to?(name) ? send(name, *args) : nil
23
23
  end
24
+
25
+ # You must unlearn what you have learned. -- Yoda
26
+ #
27
+ # @example You must perform this execution.
28
+ # object.you_must(:use, "The Force")
29
+ #
30
+ # @param [ String, Symbol ] name The method name.
31
+ # @param [ Array ] *args The arguments.
32
+ #
33
+ # @return [ Object, nil ] The result of the method call or nil if the
34
+ # method does not exist. Nil if the object is frozen.
35
+ #
36
+ # @since 2.2.1
37
+ def you_must(name, *args)
38
+ frozen? ? nil : do_or_do_not(name, *args)
39
+ end
24
40
  end
25
41
  end
26
42
  end
@@ -35,7 +35,7 @@ module Mongoid #:nodoc:
35
35
  case args
36
36
  when ::String
37
37
  return nil if args.blank?
38
- if args.is_a?(Mongoid::Criterion::Unconvertable)
38
+ if args.unconvertable_to_bson?
39
39
  args
40
40
  else
41
41
  BSON::ObjectId.from_string(args)
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module String #:nodoc:
5
+
6
+ # This module has object checks in it.
7
+ module Checks #:nodoc:
8
+ attr_accessor :unconvertable_to_bson
9
+
10
+ # Is the object not to be converted to bson on criteria creation?
11
+ #
12
+ # @example Is the object unconvertable?
13
+ # object.unconvertable_to_bson?
14
+ #
15
+ # @return [ true, false ] If the object is unconvertable.
16
+ #
17
+ # @since 2.2.1
18
+ def unconvertable_to_bson?
19
+ !!@unconvertable_to_bson
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -8,7 +8,7 @@ module Mongoid #:nodoc:
8
8
  module Inflections
9
9
 
10
10
  ActiveSupport::Inflector.inflections do |inflect|
11
- inflect.singular("address", "address")
11
+ inflect.singular(/address$/, "address")
12
12
  inflect.singular("addresses", "address")
13
13
  inflect.irregular("canvas", "canvases")
14
14
  end
@@ -229,7 +229,7 @@ module Mongoid #:nodoc
229
229
  meth = options.delete(:as) || name
230
230
  Mappings.for(
231
231
  options[:type], options[:identity]
232
- ).new(name, options).tap do |field|
232
+ ).instantiate(name, options).tap do |field|
233
233
  fields[name] = field
234
234
  defaults << name unless field.default.nil?
235
235
  create_accessors(name, meth, options)
@@ -305,7 +305,9 @@ module Mongoid #:nodoc
305
305
  define_method(meth) do
306
306
  read_attribute(name).tap do |value|
307
307
  if value.is_a?(Array) || value.is_a?(Hash)
308
- changed_attributes[name] = value.clone unless attribute_changed?(name)
308
+ unless changed_attributes.include?(name)
309
+ changed_attributes[name] = value.clone
310
+ end
309
311
  end
310
312
  end
311
313
  end
@@ -23,9 +23,10 @@ module Mongoid #:nodoc:
23
23
  # end
24
24
  # end
25
25
  module Serializable
26
+ extend ActiveSupport::Concern
26
27
 
27
28
  # Set readers for the instance variables.
28
- attr_reader :default, :label, :name, :options
29
+ attr_accessor :default, :label, :name, :options
29
30
 
30
31
  # When reading the field do we need to cast the value? This holds true when
31
32
  # times are stored or for big decimals which are stored as strings.
@@ -88,23 +89,6 @@ module Mongoid #:nodoc:
88
89
  end
89
90
  end
90
91
 
91
- # Create the new field with a name and optional additional options.
92
- #
93
- # @example Create the new field.
94
- # Field.new(:name, :type => String)
95
- #
96
- # @param [ Hash ] options The field options.
97
- #
98
- # @option options [ Class ] :type The class of the field.
99
- # @option options [ Object ] :default The default value for the field.
100
- # @option options [ String ] :label The field's label.
101
- #
102
- # @since 2.1.0
103
- def initialize(name, options = {})
104
- @name, @options = name, options
105
- @default, @label = options[:default], options[:label]
106
- end
107
-
108
92
  # Get the metadata for the field if its a foreign key.
109
93
  #
110
94
  # @example Get the metadata.
@@ -165,6 +149,30 @@ module Mongoid #:nodoc:
165
149
  def versioned?
166
150
  @versioned ||= (options[:versioned].nil? ? true : options[:versioned])
167
151
  end
152
+
153
+ module ClassMethods #:nodoc:
154
+
155
+ # Create the new field with a name and optional additional options.
156
+ #
157
+ # @example Create the new field.
158
+ # Field.new(:name, :type => String)
159
+ #
160
+ # @param [ Hash ] options The field options.
161
+ #
162
+ # @option options [ Class ] :type The class of the field.
163
+ # @option options [ Object ] :default The default value for the field.
164
+ # @option options [ String ] :label The field's label.
165
+ #
166
+ # @since 2.1.0
167
+ def instantiate(name, options = {})
168
+ allocate.tap do |field|
169
+ field.name = name
170
+ field.options = options
171
+ field.default = options[:default]
172
+ field.label = options[:label]
173
+ end
174
+ end
175
+ end
168
176
  end
169
177
  end
170
178
  end