mongoid 7.0.3 → 7.0.8

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 (102) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +1 -0
  4. data/LICENSE +1 -0
  5. data/README.md +3 -2
  6. data/Rakefile +12 -0
  7. data/lib/mongoid.rb +2 -1
  8. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  9. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  10. data/lib/mongoid/association/proxy.rb +1 -1
  11. data/lib/mongoid/association/relatable.rb +23 -21
  12. data/lib/mongoid/atomic.rb +13 -3
  13. data/lib/mongoid/atomic/paths/embedded.rb +1 -1
  14. data/lib/mongoid/attributes.rb +28 -20
  15. data/lib/mongoid/attributes/dynamic.rb +15 -14
  16. data/lib/mongoid/config/environment.rb +21 -8
  17. data/lib/mongoid/copyable.rb +5 -1
  18. data/lib/mongoid/criteria.rb +7 -1
  19. data/lib/mongoid/criteria/modifiable.rb +13 -2
  20. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  21. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  22. data/lib/mongoid/criteria/queryable/key.rb +67 -8
  23. data/lib/mongoid/criteria/queryable/mergeable.rb +5 -4
  24. data/lib/mongoid/criteria/queryable/selectable.rb +3 -4
  25. data/lib/mongoid/criteria/queryable/selector.rb +9 -31
  26. data/lib/mongoid/extensions/hash.rb +4 -2
  27. data/lib/mongoid/extensions/regexp.rb +1 -1
  28. data/lib/mongoid/extensions/string.rb +5 -3
  29. data/lib/mongoid/fields.rb +2 -1
  30. data/lib/mongoid/matchable.rb +14 -15
  31. data/lib/mongoid/matchable/all.rb +4 -3
  32. data/lib/mongoid/matchable/default.rb +71 -24
  33. data/lib/mongoid/matchable/regexp.rb +2 -2
  34. data/lib/mongoid/persistable/pushable.rb +11 -2
  35. data/lib/mongoid/persistence_context.rb +6 -6
  36. data/lib/mongoid/positional.rb +1 -1
  37. data/lib/mongoid/query_cache.rb +3 -2
  38. data/lib/mongoid/validatable/macros.rb +1 -1
  39. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  40. data/lib/mongoid/version.rb +2 -1
  41. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  42. data/spec/README.md +18 -0
  43. data/spec/app/models/delegating_patient.rb +16 -0
  44. data/spec/app/models/other_owner_object.rb +2 -0
  45. data/spec/integration/app_spec.rb +192 -0
  46. data/spec/integration/associations/embedded_spec.rb +62 -0
  47. data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
  48. data/spec/integration/document_spec.rb +22 -0
  49. data/spec/integration/matchable_spec.rb +680 -0
  50. data/spec/lite_spec_helper.rb +15 -5
  51. data/spec/mongoid/association/embedded/embedded_in_spec.rb +58 -0
  52. data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
  53. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  54. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +6 -0
  55. data/spec/mongoid/association/embedded/embeds_one_models.rb +51 -0
  56. data/spec/mongoid/association/embedded/embeds_one_spec.rb +46 -0
  57. data/spec/mongoid/association/referenced/belongs_to_spec.rb +23 -6
  58. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +2 -1
  59. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  60. data/spec/mongoid/association/referenced/has_one_spec.rb +12 -2
  61. data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
  62. data/spec/mongoid/attributes_spec.rb +19 -7
  63. data/spec/mongoid/clients/factory_spec.rb +2 -2
  64. data/spec/mongoid/clients/options_spec.rb +4 -4
  65. data/spec/mongoid/clients/sessions_spec.rb +20 -7
  66. data/spec/mongoid/clients/transactions_spec.rb +36 -15
  67. data/spec/mongoid/clients_spec.rb +2 -2
  68. data/spec/mongoid/contextual/atomic_spec.rb +20 -10
  69. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  70. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  71. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  72. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  73. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
  74. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  75. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  76. data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
  77. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
  78. data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
  79. data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
  80. data/spec/mongoid/criteria_spec.rb +7 -2
  81. data/spec/mongoid/document_fields_spec.rb +88 -0
  82. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  83. data/spec/mongoid/extensions/string_spec.rb +35 -7
  84. data/spec/mongoid/indexable_spec.rb +6 -4
  85. data/spec/mongoid/matchable/default_spec.rb +10 -3
  86. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  87. data/spec/mongoid/matchable_spec.rb +2 -2
  88. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  89. data/spec/mongoid/query_cache_spec.rb +2 -1
  90. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  91. data/spec/mongoid/scopable_spec.rb +2 -1
  92. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  93. data/spec/mongoid/tasks/database_spec.rb +1 -1
  94. data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
  95. data/spec/spec_helper.rb +4 -37
  96. data/spec/support/child_process_helper.rb +76 -0
  97. data/spec/support/cluster_config.rb +158 -0
  98. data/spec/support/constraints.rb +29 -19
  99. data/spec/support/expectations.rb +17 -3
  100. data/spec/support/spec_config.rb +12 -4
  101. metadata +525 -464
  102. metadata.gz.sig +2 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f9840f2a5bdcfd628358c56f70818857080118680059a6ca299c6de3b4554c2
4
- data.tar.gz: f8700656e769546f2c8d2555013aa601d10552e9e48faf37f24c66fded700b1d
3
+ metadata.gz: ef78cc81c2ff0304744dfd71a941ccb445860abea33dc7b2afd99058a0949bf2
4
+ data.tar.gz: 99cd2f0255d3ccb8a5487f35a39cd54a01e482602191f117cde26780ecd02037
5
5
  SHA512:
6
- metadata.gz: a05fb92510939cf2ccff55855219033db8a9a45399865f725e695af95a9501f72a0db72422766dd54fc9946854e0065b9beb870bfeb3a02b8ac9e605962419e0
7
- data.tar.gz: 267ff19b100ca5ef83f383ddd8d4ece8ce0e122a16cbc6c1605bc872e391ad775bd6336beb53af733ba8d7b47d9ec01d9842f5502c7f0c135cdc2fa258b80b47
6
+ metadata.gz: 57c42d28d64c7cb07cd6f67b4428bdb9565119df4428075d2c93502b270bb42f4446fa41aaf1e698ab5b47b5d6623389a1c13b2e67d6a30330699fed19958d69
7
+ data.tar.gz: 1f510169b514e67dd7c4c1692e829af73848c8997d03752dda28a8edc054f79a9679298004776a0b9fb059d7e35debaae51b1981b71f47dc7a0d89edacec8ac9
@@ -0,0 +1,2 @@
1
+ t���G��*l:�Ӓt s �N���{�Be�&"� �vgG���耧d_�y��0�Xb�^��#1�b ��
2
+ ߱ꗚ�v�P��o�[���������������H�4b�����)<�-E!��<j�fꏲ/ny� s����P��!p���T$g�lj��&�31�F/Ӟ�D�ɶ ; �n)�<� O�t>wq�A� k�<6��tk��C
@@ -0,0 +1 @@
1
+ �b��1C�&��~N���VwM$YF%l&S_+�S_������*������Aش�����qy��3ʬ�@Gߨ�gaB���1sX9��ik��m9~�'��v6@,Ⱦ�D��:�p$[<vL�\��D�bw䕖h�=[jg�r�5ߖ��y㜽(-����b ؾ��Ƌ����>QTTn-���mk߬B<:�}���ٌ ��myX?'{��Rf fk��O3bNj(�7�j�$�4j�)�wۂ�*�M21D2�>�����Siˆ
data/LICENSE CHANGED
@@ -1,4 +1,5 @@
1
1
  Copyright (c) 2009-2016 Durran Jordan
2
+ Copyright (c) 2015-2020 MongoDB, Inc.
2
3
 
3
4
  Permission is hereby granted, free of charge, to any person obtaining
4
5
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -14,7 +14,7 @@ Project Tracking
14
14
  ----------------
15
15
 
16
16
  * [Mongoid Website and Documentation](http://mongoid.org)
17
- * [Mongoid Google Group](http://groups.google.com/group/mongoid)
17
+ * [MongoDB Community Forum](https://developer.mongodb.com/community/forums/tags/c/drivers-odms-connectors/7/mongoid-odm)
18
18
  * [Stackoverflow](http://stackoverflow.com/questions/tagged/mongoid)
19
19
  * [#mongoid](http://webchat.freenode.net/?channels=mongoid) on freenode IRC
20
20
 
@@ -31,7 +31,8 @@ Please see the [MongoDB website](http://docs.mongodb.org/ecosystem/tutorial/ruby
31
31
  License
32
32
  -------
33
33
 
34
- Copyright (c) 2009-2017 Durran Jordan
34
+ Copyright (c) 2009-2016 Durran Jordan
35
+ Copyright (c) 2015-2020 MongoDB, Inc.
35
36
 
36
37
  Permission is hereby granted, free of charge, to any person obtaining
37
38
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -33,3 +33,15 @@ RSpec::Core::RakeTask.new('spec:progress') do |spec|
33
33
  end
34
34
 
35
35
  task :default => :spec
36
+
37
+ desc "Generate all documentation"
38
+ task :docs => 'docs:yard'
39
+
40
+ namespace :docs do
41
+ desc "Generate yard documention"
42
+ task :yard do
43
+ out = File.join('yard-docs', Mongoid::VERSION)
44
+ FileUtils.rm_rf(out)
45
+ system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
46
+ end
47
+ end
@@ -13,6 +13,7 @@ require "active_support/time_with_zone"
13
13
  require "active_model"
14
14
 
15
15
  require "mongo"
16
+ require 'mongo/active_support'
16
17
 
17
18
  require "mongoid/version"
18
19
  require "mongoid/config"
@@ -101,5 +102,5 @@ module Mongoid
101
102
  # Mongoid.database = Mongo::Connection.new.db("test")
102
103
  #
103
104
  # @since 1.0.0
104
- delegate(*(Config.public_instance_methods(false) - [ :logger=, :logger ] << { to: Config }))
105
+ delegate(*(Config.public_instance_methods(false) - [ :logger=, :logger ]), to: Config)
105
106
  end
@@ -197,7 +197,8 @@ module Mongoid
197
197
  def determine_inverses(other)
198
198
  matches = relation_class.relations.values.select do |rel|
199
199
  relation_complements.include?(rel.class) &&
200
- rel.relation_class_name == inverse_class_name
200
+ # https://jira.mongodb.org/browse/MONGOID-4882
201
+ rel.relation_class_name.sub(/\A::/, '') == inverse_class_name
201
202
  end
202
203
  if matches.size > 1
203
204
  raise Errors::AmbiguousRelationship.new(relation_class, @owner_class, name, matches)
@@ -159,7 +159,8 @@ module Mongoid
159
159
  def determine_inverses(other)
160
160
  matches = relation_class.relations.values.select do |rel|
161
161
  relation_complements.include?(rel.class) &&
162
- rel.relation_class_name == inverse_class_name
162
+ # https://jira.mongodb.org/browse/MONGOID-4882
163
+ rel.relation_class_name.sub(/\A::/, '') == inverse_class_name
163
164
 
164
165
  end
165
166
  if matches.size > 1
@@ -12,7 +12,7 @@ module Mongoid
12
12
  # We undefine most methods to get them sent through to the target.
13
13
  instance_methods.each do |method|
14
14
  undef_method(method) unless
15
- method =~ /^(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)$/
15
+ method =~ /\A(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)\z/
16
16
  end
17
17
 
18
18
  include Threaded::Lifecycle
@@ -145,20 +145,19 @@ module Mongoid
145
145
  # @since 7.0
146
146
  def inverse_type; end
147
147
 
148
- # The class name of the relation object(s).
148
+ # The class name, possibly unqualified or :: prefixed, of the association
149
+ # object(s).
149
150
  #
150
- # The class name may be fully qualified or may be specified relative
151
- # to the class on which the association is defined (this class is
152
- # accessible as inverse_class). If :class_name option is given in the
153
- # association, the exact value of that option is returned here for
154
- # backwards compatibility reasons. If :class_name option is not given,
155
- # the name of the class computed by Mongoid to be the association target
156
- # is returned, and it will be fully qualified.
151
+ # This method returns the class name as it is used in the association
152
+ # definition. If :class_name option is given in the association, the
153
+ # exact value of that option is returned here. If :class_name option is
154
+ # not given, the name of the class is calculated from association name
155
+ # but is not resolved to the actual class.
157
156
  #
158
157
  # The class name returned by this method may not correspond to a defined
159
- # class. The return value of the method is the class name that Mongoid
160
- # would reference, relative to the host document class, when it needs to
161
- # perform operations on the association target.
158
+ # class, either because the corresponding class has not been loaded yet,
159
+ # or because the association references a non-existent class altogether.
160
+ # To obtain the association class, use +relation_class+ method.
162
161
  #
163
162
  # @note The return value of this method should not be used to determine
164
163
  # whether two associations have the same target class, because the
@@ -170,15 +169,7 @@ module Mongoid
170
169
  #
171
170
  # @since 7.0
172
171
  def relation_class_name
173
- @class_name ||= @options[:class_name] || begin
174
- cls_name = ActiveSupport::Inflector.classify(name)
175
- begin
176
- cls_name = resolve_name(inverse_class, cls_name).name
177
- rescue NameError
178
- # ignore
179
- end
180
- cls_name
181
- end
172
+ @class_name ||= @options[:class_name] || ActiveSupport::Inflector.classify(name)
182
173
  end
183
174
  alias :class_name :relation_class_name
184
175
 
@@ -478,10 +469,21 @@ module Mongoid
478
469
 
479
470
  # Resolves the given class/module name in the context of the specified
480
471
  # module, as Ruby would when a constant is referenced in the source.
472
+ #
473
+ # @note This method can swallow exceptions produced during class loading,
474
+ # because it rescues NameError internally. Since this method attempts
475
+ # to load classes, failure during the loading process may also lead to
476
+ # there being incomplete class definitions.
481
477
  def resolve_name(mod, name)
482
478
  cls = exc = nil
483
479
  parts = name.to_s.split('::')
484
- namespace_hierarchy(mod).each do |ns|
480
+ if parts.first == ''
481
+ parts.shift
482
+ hierarchy = [Object]
483
+ else
484
+ hierarchy = namespace_hierarchy(mod)
485
+ end
486
+ hierarchy.each do |ns|
485
487
  begin
486
488
  parts.each do |part|
487
489
  # Simple const_get sometimes pulls names out of weird scopes,
@@ -36,7 +36,9 @@ module Mongoid
36
36
  # @since 2.2.0
37
37
  def add_atomic_pull(document)
38
38
  document.flagged_for_destroy = true
39
- (delayed_atomic_pulls[document.association_name.to_s] ||= []).push(document)
39
+ key = document.association_name.to_s
40
+ delayed_atomic_pulls[key] ||= []
41
+ delayed_atomic_pulls[key] << document
40
42
  end
41
43
 
42
44
  # Add an atomic unset for the document.
@@ -51,7 +53,9 @@ module Mongoid
51
53
  # @since 3.0.0
52
54
  def add_atomic_unset(document)
53
55
  document.flagged_for_destroy = true
54
- (delayed_atomic_unsets[document.association_name.to_s] ||= []).push(document)
56
+ key = document.association_name.to_s
57
+ delayed_atomic_unsets[key] ||= []
58
+ delayed_atomic_unsets[key] << document
55
59
  end
56
60
 
57
61
  # Returns path of the attribute for modification
@@ -189,7 +193,13 @@ module Mongoid
189
193
  #
190
194
  # @since 2.1.0
191
195
  def atomic_paths
192
- @atomic_paths ||= _association ? _association.path(self) : Atomic::Paths::Root.new(self)
196
+ @atomic_paths ||= begin
197
+ if _association
198
+ _association.path(self)
199
+ else
200
+ Atomic::Paths::Root.new(self)
201
+ end
202
+ end
193
203
  end
194
204
 
195
205
  # Get all the attributes that need to be pulled.
@@ -20,7 +20,7 @@ module Mongoid
20
20
  #
21
21
  # @since 2.1.0
22
22
  def path
23
- @path ||= position.sub(/\.\d+$/, "")
23
+ @path ||= position.sub(/\.\d+\z/, "")
24
24
  end
25
25
  end
26
26
  end
@@ -157,21 +157,21 @@ module Mongoid
157
157
  #
158
158
  # @since 1.0.0
159
159
  def write_attribute(name, value)
160
- access = database_field_name(name)
161
- if attribute_writable?(access)
160
+ field_name = database_field_name(name)
161
+ if attribute_writable?(field_name)
162
162
  _assigning do
163
- validate_attribute_value(access, value)
164
- localized = fields[access].try(:localized?)
163
+ validate_attribute_value(field_name, value)
164
+ localized = fields[field_name].try(:localized?)
165
165
  attributes_before_type_cast[name.to_s] = value
166
- typed_value = typed_value_for(access, value)
167
- unless attributes[access] == typed_value || attribute_changed?(access)
168
- attribute_will_change!(access)
166
+ typed_value = typed_value_for(field_name, value)
167
+ unless attributes[field_name] == typed_value || attribute_changed?(field_name)
168
+ attribute_will_change!(field_name)
169
169
  end
170
170
  if localized
171
- attributes[access] ||= {}
172
- attributes[access].merge!(typed_value)
171
+ attributes[field_name] ||= {}
172
+ attributes[field_name].merge!(typed_value)
173
173
  else
174
- attributes[access] = typed_value
174
+ attributes[field_name] = typed_value
175
175
  end
176
176
  typed_value
177
177
  end
@@ -337,20 +337,28 @@ module Mongoid
337
337
 
338
338
  private
339
339
 
340
- # Validates an attribute value. This provides validation checking if
341
- # the value is valid for given a field.
342
- # For now, only Hash and Array fields are validated.
340
+ # Validates an attribute value as being assignable to the specified field.
343
341
  #
344
- # @param [ String, Symbol ] access The name of the attribute to validate.
345
- # @param [ Object ] value The to be validated.
342
+ # For now, only Hash and Array fields are validated, and the value is
343
+ # being checked to be of an appropriate type (i.e. either Hash or Array,
344
+ # respectively, or nil).
345
+ #
346
+ # This method takes the name of the field as stored in the document
347
+ # in the database, not (necessarily) the Ruby method name used to read/write
348
+ # the said field.
349
+ #
350
+ # @param [ String, Symbol ] field_name The name of the field.
351
+ # @param [ Object ] value The value to be validated.
346
352
  #
347
353
  # @since 3.0.10
348
- def validate_attribute_value(access, value)
349
- return unless fields[access] && value
354
+ def validate_attribute_value(field_name, value)
355
+ return if value.nil?
356
+ field = fields[field_name]
357
+ return unless field
350
358
  validatable_types = [ Hash, Array ]
351
- if validatable_types.include? fields[access].type
352
- unless value.is_a? fields[access].type
353
- raise Mongoid::Errors::InvalidValue.new(fields[access].type, value.class)
359
+ if validatable_types.include?(field.type)
360
+ unless value.is_a?(field.type)
361
+ raise Mongoid::Errors::InvalidValue.new(field.type, value.class)
354
362
  end
355
363
  end
356
364
  end
@@ -38,12 +38,13 @@ module Mongoid
38
38
  # @since 4.0.0
39
39
  def define_dynamic_reader(name)
40
40
  return unless name.valid_method_name?
41
- class_eval <<-READER, __FILE__, __LINE__ + 1
42
- def #{name}
43
- attribute_will_change!(#{name.inspect})
44
- read_raw_attribute(#{name.inspect})
41
+
42
+ class_eval do
43
+ define_method(name) do
44
+ attribute_will_change!(name)
45
+ read_raw_attribute(name)
45
46
  end
46
- READER
47
+ end
47
48
  end
48
49
 
49
50
  # Define a reader method for a dynamic attribute before type cast.
@@ -57,12 +58,12 @@ module Mongoid
57
58
  #
58
59
  # @since 4.0.0
59
60
  def define_dynamic_before_type_cast_reader(name)
60
- class_eval <<-READER, __FILE__, __LINE__ + 1
61
- def #{name}_before_type_cast
62
- attribute_will_change!(#{name.inspect})
63
- read_attribute_before_type_cast(#{name.inspect})
61
+ class_eval do
62
+ define_method("#{name}_before_type_cast") do
63
+ attribute_will_change!(name)
64
+ read_attribute_before_type_cast(name)
64
65
  end
65
- READER
66
+ end
66
67
  end
67
68
 
68
69
  # Define a writer method for a dynamic attribute.
@@ -78,11 +79,11 @@ module Mongoid
78
79
  def define_dynamic_writer(name)
79
80
  return unless name.valid_method_name?
80
81
 
81
- class_eval <<-WRITER, __FILE__, __LINE__ + 1
82
- def #{name}=(value)
83
- write_attribute(#{name.inspect}, value)
82
+ class_eval do
83
+ define_method("#{name}=") do |value|
84
+ write_attribute(name, value)
84
85
  end
85
- WRITER
86
+ end
86
87
  end
87
88
 
88
89
  # If the attribute is dynamic, add a field for it with a type of object
@@ -6,35 +6,48 @@ module Mongoid
6
6
  module Environment
7
7
  extend self
8
8
 
9
- # Get the name of the environment that we are running under. This first
10
- # looks for Rails, then Sinatra, then a RACK_ENV environment variable,
11
- # and if none of those are found raises an error.
9
+ # Get the name of the environment that Mongoid is running under.
10
+ #
11
+ # Uses the following sources in order:
12
+ # - If +::Rails+ is defined, +Rails.env+.
13
+ # - If +::Sinatra+ is defined, +Sinatra::Base.environment+.
14
+ # - +RACK_ENV+
15
+ # - +MONGOID_ENV*
12
16
  #
13
17
  # @example Get the env name.
14
18
  # Environment.env_name
15
19
  #
16
- # @raise [ Errors::NoEnvironment ] If no environment was set.
20
+ # @raise [ Errors::NoEnvironment ] If environment name cannot be
21
+ # determined because none of the sources was set.
17
22
  #
18
23
  # @return [ String ] The name of the current environment.
19
24
  #
20
25
  # @since 2.3.0
26
+ # @api public
21
27
  def env_name
22
- return Rails.env if defined?(Rails) && Rails.respond_to?(:env)
23
- return Sinatra::Base.environment.to_s if defined?(Sinatra)
24
- ENV["RACK_ENV"] || ENV["MONGOID_ENV"] || raise(Errors::NoEnvironment.new)
28
+ if defined?(::Rails)
29
+ return ::Rails.env
30
+ end
31
+ if defined?(::Sinatra)
32
+ return ::Sinatra::Base.environment.to_s
33
+ end
34
+ ENV["RACK_ENV"] || ENV["MONGOID_ENV"] or raise Errors::NoEnvironment
25
35
  end
26
36
 
27
37
  # Load the yaml from the provided path and return the settings for the
28
- # current environment.
38
+ # specified environment, or for the current Mongoid environment.
29
39
  #
30
40
  # @example Load the yaml.
31
41
  # Environment.load_yaml("/work/mongoid.yml")
32
42
  #
33
43
  # @param [ String ] path The location of the file.
44
+ # @param [ String | Symbol ] environment Optional environment name to
45
+ # override the current Mongoid environment.
34
46
  #
35
47
  # @return [ Hash ] The settings.
36
48
  #
37
49
  # @since 2.3.0
50
+ # @api private
38
51
  def load_yaml(path, environment = nil)
39
52
  env = environment ? environment.to_s : env_name
40
53
  YAML.load(ERB.new(File.new(path).read).result)[env]
@@ -74,7 +74,11 @@ module Mongoid
74
74
 
75
75
  if association.is_a?(Association::Embedded::EmbedsMany)
76
76
  attrs[association.key].each do |attr|
77
- embedded_klass = attr.fetch('_type', association.relation_class_name).constantize
77
+ embedded_klass = if type = attr['_type']
78
+ type.constantize
79
+ else
80
+ association.relation_class
81
+ end
78
82
  process_localized_attributes(embedded_klass, attr)
79
83
  end
80
84
  else
@@ -435,7 +435,13 @@ module Mongoid
435
435
  #
436
436
  # @since 3.1.0
437
437
  def for_js(javascript, scope = {})
438
- js_query(BSON::CodeWithScope.new(javascript, scope))
438
+ code = if scope.empty?
439
+ # CodeWithScope is not supported for $where as of MongoDB 4.4
440
+ BSON::Code.new(javascript)
441
+ else
442
+ BSON::CodeWithScope.new(javascript, scope)
443
+ end
444
+ js_query(code)
439
445
  end
440
446
 
441
447
  private
@@ -3,6 +3,10 @@ module Mongoid
3
3
  class Criteria
4
4
  module Modifiable
5
5
 
6
+ # @attribute [r] create_attrs Additional attributes to add to the Document upon creation.
7
+ # @api private
8
+ attr_reader :create_attrs
9
+
6
10
  # Build a document given the selector and return it.
7
11
  # Complex criteria, such as $in and $or operations will get ignored.
8
12
  #
@@ -57,6 +61,9 @@ module Mongoid
57
61
 
58
62
  # Define attributes with which new documents will be created.
59
63
  #
64
+ # Note that if `find_or_create_by` is called after this in a method chain, the attributes in
65
+ # the query will override those from this method.
66
+ #
60
67
  # @example Define attributes to be used when a new document is created.
61
68
  # Person.create_with(job: 'Engineer').find_or_create_by(employer: 'MongoDB')
62
69
  #
@@ -64,7 +71,10 @@ module Mongoid
64
71
  #
65
72
  # @since 5.1.0
66
73
  def create_with(attrs = {})
67
- where(selector.merge(attrs))
74
+ tap do
75
+ @create_attrs ||= {}
76
+ @create_attrs.update(attrs)
77
+ end
68
78
  end
69
79
 
70
80
  # Find the first +Document+ given the conditions, or creates a new document
@@ -172,7 +182,8 @@ module Mongoid
172
182
  #
173
183
  # @since 3.0.0
174
184
  def create_document(method, attrs = nil, &block)
175
- attributes = selector.reduce(attrs ? attrs.dup : {}) do |hash, (key, value)|
185
+ attrs = (create_attrs || {}).merge(attrs || {})
186
+ attributes = selector.reduce(attrs) do |hash, (key, value)|
176
187
  unless invalid_key?(hash, key) || invalid_embedded_doc?(value)
177
188
  hash[key] = value
178
189
  end