mongoid 4.0.0.alpha2 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +3 -3
  4. data/lib/config/locales/en.yml +13 -0
  5. data/lib/mongoid.rb +3 -1
  6. data/lib/mongoid/atomic.rb +1 -1
  7. data/lib/mongoid/atomic/paths/embedded/many.rb +1 -1
  8. data/lib/mongoid/atomic/paths/embedded/one.rb +1 -1
  9. data/lib/mongoid/attributes.rb +23 -1
  10. data/lib/mongoid/attributes/processing.rb +1 -1
  11. data/lib/mongoid/composable.rb +3 -2
  12. data/lib/mongoid/contextual/command.rb +0 -26
  13. data/lib/mongoid/contextual/geo_near.rb +1 -1
  14. data/lib/mongoid/contextual/mongo.rb +6 -29
  15. data/lib/mongoid/contextual/text_search.rb +3 -5
  16. data/lib/mongoid/criteria.rb +1 -1
  17. data/lib/mongoid/criteria/modifiable.rb +27 -7
  18. data/lib/mongoid/criteria/permission.rb +70 -0
  19. data/lib/mongoid/document.rb +5 -6
  20. data/lib/mongoid/errors.rb +2 -0
  21. data/lib/mongoid/errors/document_not_destroyed.rb +25 -0
  22. data/lib/mongoid/errors/readonly_document.rb +24 -0
  23. data/lib/mongoid/extensions/boolean.rb +1 -0
  24. data/lib/mongoid/extensions/hash.rb +1 -1
  25. data/lib/mongoid/factory.rb +5 -3
  26. data/lib/mongoid/fields.rb +32 -0
  27. data/lib/mongoid/fields/localized.rb +1 -1
  28. data/lib/mongoid/fields/standard.rb +1 -1
  29. data/lib/mongoid/findable.rb +1 -0
  30. data/lib/mongoid/interceptable.rb +11 -6
  31. data/lib/mongoid/log_subscriber.rb +34 -1
  32. data/lib/mongoid/persistable/deletable.rb +1 -0
  33. data/lib/mongoid/persistable/destroyable.rb +7 -2
  34. data/lib/mongoid/persistable/updatable.rb +27 -26
  35. data/lib/mongoid/query_cache.rb +246 -0
  36. data/lib/mongoid/railties/database.rake +4 -26
  37. data/lib/mongoid/relations.rb +8 -22
  38. data/lib/mongoid/relations/accessors.rb +0 -3
  39. data/lib/mongoid/relations/binding.rb +1 -1
  40. data/lib/mongoid/relations/bindings/embedded/in.rb +1 -1
  41. data/lib/mongoid/relations/eager.rb +5 -6
  42. data/lib/mongoid/relations/eager/base.rb +97 -5
  43. data/lib/mongoid/relations/eager/belongs_to.rb +1 -0
  44. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +16 -9
  45. data/lib/mongoid/relations/eager/has_many.rb +1 -0
  46. data/lib/mongoid/relations/eager/has_one.rb +1 -0
  47. data/lib/mongoid/relations/embedded/batchable.rb +1 -1
  48. data/lib/mongoid/relations/embedded/in.rb +4 -4
  49. data/lib/mongoid/relations/embedded/many.rb +7 -5
  50. data/lib/mongoid/relations/embedded/one.rb +1 -1
  51. data/lib/mongoid/relations/macros.rb +1 -0
  52. data/lib/mongoid/relations/marshalable.rb +3 -3
  53. data/lib/mongoid/relations/proxy.rb +12 -10
  54. data/lib/mongoid/relations/referenced/in.rb +2 -2
  55. data/lib/mongoid/relations/referenced/many.rb +9 -9
  56. data/lib/mongoid/relations/referenced/many_to_many.rb +7 -7
  57. data/lib/mongoid/relations/referenced/one.rb +4 -4
  58. data/lib/mongoid/{state.rb → stateful.rb} +13 -1
  59. data/lib/mongoid/tasks/database.rake +31 -0
  60. data/lib/mongoid/tasks/database.rb +107 -0
  61. data/lib/mongoid/threaded.rb +0 -47
  62. data/lib/mongoid/validatable/uniqueness.rb +4 -16
  63. data/lib/mongoid/version.rb +1 -1
  64. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +0 -3
  65. data/lib/rails/mongoid.rb +0 -124
  66. data/spec/app/models/edit.rb +5 -0
  67. data/spec/app/models/even.rb +7 -0
  68. data/spec/app/models/line_item.rb +1 -1
  69. data/spec/app/models/note.rb +2 -0
  70. data/spec/app/models/odd.rb +7 -0
  71. data/spec/app/models/record.rb +5 -0
  72. data/spec/app/models/wiki_page.rb +1 -1
  73. data/spec/mongoid/attributes_spec.rb +76 -1
  74. data/spec/mongoid/changeable_spec.rb +6 -2
  75. data/spec/mongoid/contextual/mongo_spec.rb +3 -1
  76. data/spec/mongoid/contextual/text_search_spec.rb +3 -1
  77. data/spec/mongoid/criteria/modifiable_spec.rb +192 -0
  78. data/spec/mongoid/criteria_spec.rb +6 -2
  79. data/spec/mongoid/errors/document_not_destroyed_spec.rb +33 -0
  80. data/spec/mongoid/errors/readonly_document_spec.rb +29 -0
  81. data/spec/mongoid/fields/localized_spec.rb +15 -0
  82. data/spec/mongoid/fields_spec.rb +88 -2
  83. data/spec/mongoid/log_subscriber_spec.rb +3 -3
  84. data/spec/mongoid/persistable/deletable_spec.rb +14 -1
  85. data/spec/mongoid/persistable/destroyable_spec.rb +45 -1
  86. data/spec/mongoid/persistable/savable_spec.rb +34 -5
  87. data/spec/mongoid/query_cache_spec.rb +197 -0
  88. data/spec/mongoid/relations/bindings/embedded/in_spec.rb +2 -2
  89. data/spec/mongoid/relations/builders/referenced/many_spec.rb +1 -1
  90. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +11 -37
  91. data/spec/mongoid/relations/eager/has_one_spec.rb +1 -1
  92. data/spec/mongoid/relations/embedded/in_spec.rb +1 -1
  93. data/spec/mongoid/relations/embedded/many_spec.rb +10 -10
  94. data/spec/mongoid/relations/embedded/one_spec.rb +10 -2
  95. data/spec/mongoid/relations/referenced/in_spec.rb +1 -1
  96. data/spec/mongoid/relations/referenced/many_spec.rb +37 -2
  97. data/spec/mongoid/relations/touchable_spec.rb +20 -0
  98. data/spec/mongoid/{state_spec.rb → stateful_spec.rb} +26 -1
  99. data/spec/mongoid/tasks/database_rake_spec.rb +285 -0
  100. data/spec/mongoid/tasks/database_spec.rb +148 -0
  101. data/spec/mongoid/validatable/uniqueness_spec.rb +7 -0
  102. data/spec/rails/mongoid_spec.rb +0 -316
  103. data/spec/spec_helper.rb +1 -0
  104. metadata +30 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a19035d46ca8c08250b25f7351b5b74a1fffd1f
4
- data.tar.gz: 5d21abf409d5f12902c313678f5ced482ef5bf9f
3
+ metadata.gz: 158b72d6477798214b724968813850224dc3657f
4
+ data.tar.gz: beff6994a7f9818cb6a956a1dbe682c66d1155f1
5
5
  SHA512:
6
- metadata.gz: d9a2567b69ffd592e74a45b345a52e2c15f1e0a049360313c847dc1b08e6ac081973d1cfb88dbae44db72f3eb3c1e4a68855916c0b70f1cae99fcc6cf8a60490
7
- data.tar.gz: 93da6b0c3d2539ea4fd3126ac238019e16d5b6060de1bf81309ecaa40ab8cb5a023f7f558f2c4fbe5db65bf7f3f98b9fdb5da541dd5502f73d4d462333c6af37
6
+ metadata.gz: d01a18d141f3883470322bf3e713bd141003d85df34b97cdc45437819ae6ded25291b6c0846fc1a59e0a9d2e88a51da50684ead9ddd4747d405157f9324c7de4
7
+ data.tar.gz: 872d41a758ecdf59a503bda991cb8677982e774e7cc2509020c2ffc0953bbac559636ed2cd0bd58a07e9099b78195f5688d91748d55025231ef78de210c36f66
@@ -7,6 +7,19 @@ For instructions on upgrading to newer versions, visit
7
7
 
8
8
  ### Major Changes (Backwards Incompatible)
9
9
 
10
+ * \#3320 Remove Rails dependencies on database rake tasks. (Arthur Neves)
11
+
12
+ All db:* rake tasks should work as before when using Rails.
13
+ When not in a Rails, just load the database tasks using:
14
+
15
+ load 'mongoid/tasks/database.rake'
16
+
17
+ * Mongoid 4 now only supports MongoDB 2.4.0 and higher.
18
+
19
+ * `Document#metadata` has been renamed to `Document#relation_metadata` to
20
+ avoid common conflicts. Relation proxies also have this renamed to the
21
+ same as well.
22
+
10
23
  * Scopes and default scopes must now all be defined within lambdas or procs.
11
24
 
12
25
  * `skip_version_check` config option was removed.
@@ -214,6 +227,11 @@ For instructions on upgrading to newer versions, visit
214
227
  * `delete_all` and `destroy_all` no longer take a `:conditions` hash but
215
228
  just the raw attributes.
216
229
 
230
+ * \#1908 Documents now loaded from criteria using `#only` or `#without` will now
231
+ raise an error when attempting to save, update, or delete these records.
232
+ Additionally fields excluded from the fields retrieved from the database will
233
+ also raise an exception when trying to access them.
234
+
217
235
  * \#1344 Atomic updates can now be executed in an `atomically` block, which will
218
236
  delay any atomic updates on the document the block was called on until the
219
237
  block is complete.
@@ -259,6 +277,16 @@ For instructions on upgrading to newer versions, visit
259
277
  ..
260
278
  end
261
279
 
280
+ * Field types can now use symbols as well as class names. See:
281
+ https://github.com/mongoid/mongoid/blob/master/lib/mongoid/fields.rb#L16
282
+ for the available mappings.
283
+
284
+ * \#3513 Documents now have a `#destroy!` method that will raise a
285
+ `Mongoid::Errors::DocumentNotDestroyed` error if a destroy callback returns
286
+ a false value.
287
+
288
+ * \#3496 Added class level and criteria level `find_or_create_by!`.
289
+
262
290
  * \#3479 Map/reduce now respects criteria no timeout options if output is not
263
291
  inline.
264
292
 
@@ -268,10 +296,19 @@ For instructions on upgrading to newer versions, visit
268
296
  Band.none
269
297
  Band.none.where(name: "Tool") # Always has zero documents.
270
298
 
299
+ * \#3410 Mongoid now has a query cache that can be used as a middleware in
300
+ Rack applications. (Arthur Neves)
301
+
302
+ For Rails:
303
+
304
+ config.middleware.use(Mongoid::QueryCache::Middleware)
305
+
271
306
  * \#3319 Counters can now be reset from a document instance:
272
307
 
273
308
  document.reset_counters(:relation)
274
309
 
310
+ * \#3310 embedded_in relations now accept a `touch` option to update parents.
311
+
275
312
  * \#3302 Aliasing using `alias_attribute` now properly handles aliases in criteria.
276
313
 
277
314
  * \#3155 Range field will persist the exclude_end when provided.
@@ -304,8 +341,21 @@ For instructions on upgrading to newer versions, visit
304
341
 
305
342
  ### Resolved Issues
306
343
 
344
+ * \#3514 Fixed query cache to work on first/last calls.
345
+
346
+ * \#3383/\#3495 Fix has_and_belongs_to_many eager load. (Arthur Neves)
347
+
348
+ * \#3492 $rename operations should not mongoize values. (Vladislav Melanitskiy)
349
+
350
+ * \#3490 Allow localized fields to work with boolean `false` values.
351
+
352
+ * \#3487 Map Boolean to Mongoid::Boolean in field definitions. (Arthur Neves)
353
+
307
354
  * \#3449 Touch needs to work for create and update. (Greggory Rothmeier)
308
355
 
356
+ * \#3347 Creating documents off of scopes for embedded relations now properly
357
+ sets the parent document on the created children.
358
+
309
359
  * \#3432 Fixed mongoization of DateTime losing precision.
310
360
 
311
361
  * \#3397 Fixed $ne matcher for embedded documents to match server behaviour.
@@ -323,6 +373,9 @@ For instructions on upgrading to newer versions, visit
323
373
 
324
374
  * \#3242 Has_many relation must use the inverse foreign_key. (Arthur Neves)
325
375
 
376
+ * \#3233 Don't double call validation callbacks when cascading children and
377
+ relation validation is turned on.
378
+
326
379
  * \#3197 Improvements in the calls to `aggregates` on root and embedded
327
380
  collections. (Wojciech Piekutowski)
328
381
 
@@ -351,6 +404,8 @@ For instructions on upgrading to newer versions, visit
351
404
 
352
405
  * \#3414 Backkport skip and limit options on aggregation. (Wojciech Piekutowski)
353
406
 
407
+ * \#3469 Fix RegexpError: failed to allocate memory: /\./ on .hash_dot_syntax? (Dmitry Krasnoukhov)
408
+
354
409
  ## 3.1.6
355
410
 
356
411
  ### Resolved Issues
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Mongoid [![Build Status](https://secure.travis-ci.org/mongoid/mongoid.png?branch=master)](http://travis-ci.org/mongoid/mongoid) [![Code Climate](https://codeclimate.com/github/mongoid/mongoid.png)](https://codeclimate.com/github/mongoid/mongoid) [![Coverage Status](https://coveralls.io/repos/mongoid/mongoid/badge.png?branch=master)](https://coveralls.io/r/mongoid/mongoid?branch=master) [![Gem Version](https://badge.fury.io/rb/mongoid.png)](http://badge.fury.io/rb/mongoid)
1
+ Mongoid [![Build Status](https://secure.travis-ci.org/mongoid/mongoid.png?branch=master)](http://travis-ci.org/mongoid/mongoid) [![Code Climate](https://codeclimate.com/github/mongoid/mongoid.png)](https://codeclimate.com/github/mongoid/mongoid) [![Coverage Status](https://coveralls.io/repos/mongoid/mongoid/badge.png?branch=master)](https://coveralls.io/r/mongoid/mongoid?branch=master) [![Gem Version](https://badge.fury.io/rb/mongoid.png)](http://badge.fury.io/rb/mongoid) [![Dependency Status](https://www.versioneye.com/ruby/mongoid/3.1.6/badge.png)](https://www.versioneye.com/ruby/mongoid/3.1.6)
2
2
  ========
3
3
 
4
4
  Mongoid is an ODM (Object-Document-Mapper) framework for MongoDB in Ruby.
@@ -9,12 +9,12 @@ Project Tracking
9
9
  * [Mongoid Website and Documentation](http://mongoid.org)
10
10
  * [Mongoid Google Group](http://groups.google.com/group/mongoid)
11
11
  * [Stackoverflow](http://stackoverflow.com/questions/tagged/mongoid)
12
- * #mongoid on freenode IRC
12
+ * [#mongoid](http://webchat.freenode.net/?channels=mongoid) on freenode IRC
13
13
 
14
14
  Compatibility
15
15
  -------------
16
16
 
17
- Mongoid is tested against MRI 1.9.3, 2.0.0, and JRuby (1.9).
17
+ Mongoid is tested against MRI 1.9.3, 2.0.0, 2.1.0 and JRuby (1.9).
18
18
 
19
19
  Documentation
20
20
  -------------
@@ -31,6 +31,13 @@ en:
31
31
  resolution: "Most likely this is caused by passing parameters directly
32
32
  through to the find, and the parameter either is not present or the
33
33
  key from which it is accessed is incorrect."
34
+ document_not_destroyed:
35
+ message: "%{klass} with id %{id} was not destroyed."
36
+ summary: "When calling %{klass}#destroy! and a callback halts the destroy
37
+ callback chain by returning a false value, the deletion will not
38
+ actually occur."
39
+ resolution: "Check the before/after destroy callbacks to ensure that the
40
+ return values are truthy for the chain to continue."
34
41
  document_not_found:
35
42
  message: "Document(s) not found for class %{klass} with id(s) %{missing}."
36
43
  summary: "When calling %{klass}.find with an id or array of ids, each
@@ -389,6 +396,12 @@ en:
389
396
  can only have values set when the document is a new record."
390
397
  resolution: "Don't define '%{name}' as readonly, or do not attempt
391
398
  to update its value after the document is persisted."
399
+ readonly_document:
400
+ message: "Attempted to persist the readonly document '%{klass}'."
401
+ summary: "Documents loaded from the database using #only
402
+ cannot be persisted."
403
+ resolution: "Don't attempt to persist documents that are flagged as
404
+ readonly."
392
405
  scope_overwrite:
393
406
  message: "Cannot create scope :%{scope_name}, because of existing
394
407
  method %{model_name}.%{scope_name}."
@@ -20,6 +20,8 @@ require "mongoid/loggable"
20
20
  require "mongoid/sessions"
21
21
  require "mongoid/document"
22
22
  require "mongoid/log_subscriber"
23
+ require "mongoid/tasks/database"
24
+ require "mongoid/query_cache"
23
25
 
24
26
  # If we are using Rails then we will include the Mongoid railtie. This has all
25
27
  # the nifty initializers that Mongoid needs.
@@ -40,7 +42,7 @@ module Mongoid
40
42
  #
41
43
  # @example Set up configuration options.
42
44
  # Mongoid.configure do |config|
43
- # config.use(name: "mongoid_test", host: "localhost", port: 27017)
45
+ # config.connect_to("mongoid_test")
44
46
  # end
45
47
  #
46
48
  # @return [ Config ] The configuration object.
@@ -189,7 +189,7 @@ module Mongoid
189
189
  #
190
190
  # @since 2.1.0
191
191
  def atomic_paths
192
- @atomic_paths ||= metadata ? metadata.path(self) : Atomic::Paths::Root.new(self)
192
+ @atomic_paths ||= __metadata ? __metadata.path(self) : Atomic::Paths::Root.new(self)
193
193
  end
194
194
 
195
195
  # Get all the attributes that need to be pulled.
@@ -35,7 +35,7 @@ module Mongoid
35
35
  def position
36
36
  pos = parent.atomic_position
37
37
  locator = document.new_record? ? "" : ".#{document._index}"
38
- "#{pos}#{"." unless pos.blank?}#{document.metadata.store_as}#{locator}"
38
+ "#{pos}#{"." unless pos.blank?}#{document.__metadata.store_as}#{locator}"
39
39
  end
40
40
  end
41
41
  end
@@ -34,7 +34,7 @@ module Mongoid
34
34
  # @since 2.1.0
35
35
  def position
36
36
  pos = parent.atomic_position
37
- "#{pos}#{"." unless pos.blank?}#{document.metadata.store_as}"
37
+ "#{pos}#{"." unless pos.blank?}#{document.__metadata.store_as}"
38
38
  end
39
39
  end
40
40
  end
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require "active_model/attribute_methods"
2
3
  require "mongoid/attributes/dynamic"
3
4
  require "mongoid/attributes/nested"
4
5
  require "mongoid/attributes/processing"
@@ -90,6 +91,9 @@ module Mongoid
90
91
  # @since 1.0.0
91
92
  def read_attribute(name)
92
93
  normalized = database_field_name(name.to_s)
94
+ if attribute_missing?(name)
95
+ raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'."
96
+ end
93
97
  if hash_dot_syntax?(normalized)
94
98
  attributes.__nested__(normalized)
95
99
  else
@@ -219,6 +223,24 @@ module Mongoid
219
223
  end
220
224
  alias :attributes= :write_attributes
221
225
 
226
+ # Determine if the attribute is missing from the document, due to loading
227
+ # it from the database with missing fields.
228
+ #
229
+ # @example Is the attribute missing?
230
+ # document.attribute_missing?("test")
231
+ #
232
+ # @param [ String ] name The name of the attribute.
233
+ #
234
+ # @return [ true, false ] If the attribute is missing.
235
+ #
236
+ # @since 4.0.0
237
+ def attribute_missing?(name)
238
+ selection = __selected_fields
239
+ return false unless selection
240
+ (selection.values.first == 0 && selection[name.to_s] == 0) ||
241
+ (selection.values.first == 1 && !selection.has_key?(name.to_s))
242
+ end
243
+
222
244
  private
223
245
 
224
246
  # Does the string contain dot syntax for accessing hashes?
@@ -232,7 +254,7 @@ module Mongoid
232
254
  #
233
255
  # @since 3.0.15
234
256
  def hash_dot_syntax?(string)
235
- string =~ /\./
257
+ string.include?(".")
236
258
  end
237
259
 
238
260
  # Return the typecasted value for a field.
@@ -19,7 +19,7 @@ module Mongoid
19
19
  def process_attributes(attrs = nil)
20
20
  attrs ||= {}
21
21
  if !attrs.empty?
22
- attrs = sanitize_for_mass_assignment(attrs.to_hash)
22
+ attrs = sanitize_for_mass_assignment(attrs)
23
23
  attrs.each_pair do |key, value|
24
24
  next if pending_attribute?(key, value)
25
25
  process_attribute(key, value)
@@ -11,6 +11,7 @@ require "mongoid/selectable"
11
11
  require "mongoid/scopable"
12
12
  require "mongoid/serializable"
13
13
  require "mongoid/shardable"
14
+ require "mongoid/stateful"
14
15
  require "mongoid/traversable"
15
16
  require "mongoid/validatable"
16
17
 
@@ -50,7 +51,7 @@ module Mongoid
50
51
  include Serializable
51
52
  include Sessions
52
53
  include Shardable
53
- include State
54
+ include Stateful
54
55
  include Threaded::Lifecycle
55
56
  include Traversable
56
57
  include Validatable
@@ -76,7 +77,7 @@ module Mongoid
76
77
  Serializable,
77
78
  Sessions,
78
79
  Shardable,
79
- State,
80
+ Stateful,
80
81
  Threaded::Lifecycle,
81
82
  Traversable,
82
83
  Validatable,
@@ -30,32 +30,6 @@ module Mongoid
30
30
  def session
31
31
  collection.database.session
32
32
  end
33
-
34
- private
35
-
36
- # Execute the block setting field limitations.
37
- #
38
- # @api private
39
- #
40
- # @example Execute with field limitations.
41
- # text_search.selecting do
42
- # #...
43
- # end
44
- #
45
- # @param [ Symbol ] param The name of the command parameter.
46
- #
47
- # @return [ Object ] The result of the yield.
48
- #
49
- # @since 4.0.0
50
- def selecting(param)
51
- begin
52
- fields = command[param]
53
- Threaded.set_selection(criteria.object_id, fields) unless fields.blank?
54
- yield
55
- ensure
56
- Threaded.delete_selection(criteria.object_id)
57
- end
58
- end
59
33
  end
60
34
  end
61
35
  end
@@ -213,7 +213,7 @@ module Mongoid
213
213
  # @since 3.0.0
214
214
  def documents
215
215
  results["results"].map do |attributes|
216
- doc = Factory.from_db(criteria.klass, attributes["obj"], criteria.object_id)
216
+ doc = Factory.from_db(criteria.klass, attributes["obj"], criteria.options[:fields])
217
217
  doc.attributes["geo_near_distance"] = attributes["dis"]
218
218
  doc
219
219
  end
@@ -119,13 +119,11 @@ module Mongoid
119
119
  # @since 3.0.0
120
120
  def each(&block)
121
121
  if block_given?
122
- selecting do
123
- documents_for_iteration.each do |doc|
124
- yield_document(doc, &block)
125
- end
126
- @cache_loaded = true
127
- self
122
+ documents_for_iteration.each do |doc|
123
+ yield_document(doc, &block)
128
124
  end
125
+ @cache_loaded = true
126
+ self
129
127
  else
130
128
  to_enum
131
129
  end
@@ -624,7 +622,7 @@ module Mongoid
624
622
  if cached? && !documents.empty?
625
623
  documents
626
624
  elsif eager_loadable?
627
- docs = query.map{ |doc| Factory.from_db(klass, doc) }
625
+ docs = query.map{ |doc| Factory.from_db(klass, doc, criteria.options[:fields]) }
628
626
  eager_load(docs)
629
627
  docs
630
628
  else
@@ -632,27 +630,6 @@ module Mongoid
632
630
  end
633
631
  end
634
632
 
635
- # If we are limiting results, we need to set the field limitations on a
636
- # thread local to avoid overriding the default values.
637
- #
638
- # @example Execute with selection.
639
- # context.selecting do
640
- # collection.find
641
- # end
642
- #
643
- # @return [ Object ] The yielded value.
644
- #
645
- # @since 2.4.4
646
- def selecting
647
- begin
648
- fields = criteria.options[:fields]
649
- Threaded.set_selection(criteria.object_id, fields) unless fields.blank?
650
- yield
651
- ensure
652
- Threaded.delete_selection(criteria.object_id)
653
- end
654
- end
655
-
656
633
  # Yield to the document.
657
634
  #
658
635
  # @api private
@@ -667,7 +644,7 @@ module Mongoid
667
644
  # @since 3.0.0
668
645
  def yield_document(document, &block)
669
646
  doc = document.respond_to?(:_id) ?
670
- document : Factory.from_db(klass, document, criteria.object_id)
647
+ document : Factory.from_db(klass, document, criteria.options[:fields])
671
648
  yield(doc)
672
649
  documents.push(doc) if cacheable?
673
650
  end
@@ -24,10 +24,8 @@ module Mongoid
24
24
  # @since 4.0.0
25
25
  def each
26
26
  if block_given?
27
- selecting(:project) do
28
- documents.each do |doc|
29
- yield doc
30
- end
27
+ documents.each do |doc|
28
+ yield doc
31
29
  end
32
30
  else
33
31
  to_enum
@@ -158,7 +156,7 @@ module Mongoid
158
156
  # @since 4.0.0
159
157
  def documents
160
158
  results["results"].map do |attributes|
161
- Factory.from_db(criteria.klass, attributes["obj"], criteria.object_id)
159
+ Factory.from_db(criteria.klass, attributes["obj"], command[:project])
162
160
  end
163
161
  end
164
162
 
@@ -31,7 +31,7 @@ module Mongoid
31
31
  # @since 4.0.0
32
32
  CHECK = []
33
33
 
34
- attr_accessor :embedded, :klass
34
+ attr_accessor :embedded, :klass, :parent_document, :metadata
35
35
 
36
36
  # Returns true if the supplied +Enumerable+ or +Criteria+ is equal to the results
37
37
  # of this +Criteria+ or the criteria itself.
@@ -68,6 +68,22 @@ module Mongoid
68
68
  find_or(:create, attrs, &block)
69
69
  end
70
70
 
71
+ # Find the first +Document+ given the conditions, or creates a new document
72
+ # with the conditions that were supplied. If validation fails an
73
+ # exception will be raised.
74
+ #
75
+ # @example Find or create the document.
76
+ # Person.find_or_create_by!(:attribute => "value")
77
+ #
78
+ # @param [ Hash ] attrs The attributes to check.
79
+ #
80
+ # @raise [ Errors::Validations ] on validation error.
81
+ #
82
+ # @return [ Document ] A matching or newly created document.
83
+ def find_or_create_by!(attrs = {}, &block)
84
+ find_or(:create!, attrs, &block)
85
+ end
86
+
71
87
  # Find the first +Document+ given the conditions, or initializes a new document
72
88
  # with the conditions that were supplied.
73
89
  #
@@ -144,13 +160,17 @@ module Mongoid
144
160
  #
145
161
  # @since 3.0.0
146
162
  def create_document(method, attrs = nil, &block)
147
- klass.__send__(method,
148
- selector.reduce(attrs || {}) do |hash, (key, value)|
149
- unless key.to_s =~ /\$/ || value.is_a?(Hash)
150
- hash[key] = value
151
- end
152
- hash
153
- end, &block)
163
+ attributes = selector.reduce(attrs || {}) do |hash, (key, value)|
164
+ unless key.to_s =~ /\$/ || value.is_a?(Hash)
165
+ hash[key] = value
166
+ end
167
+ hash
168
+ end
169
+ if embedded?
170
+ attributes[:_parent] = parent_document
171
+ attributes[:__metadata] = metadata
172
+ end
173
+ klass.__send__(method, attributes, &block)
154
174
  end
155
175
 
156
176
  # Find the first object or create/initialize it.