Skip to content

Commit 3a5329f

Browse files
p-mongop
andauthored
MONGOID-5247 change feature flag names to be reflective of user-visible behavior (#5163)
* doc tweak * MONGOID-5195 MONGOID-5237 reword compare_time_by_ms description * MONGOID-5151 MONGOID-5233 broken_alias_handling * MONGOID-5183 MONGOID-5236 broken_and * MONGOID-5186 MONGOID-5229 broken_scoping * MONGOID-4755 MONGOID-5239 broken_aggregables * MONGOID-5126 MONGOID-5232 broken_triple_equals * more triple equals tests * MONGOID-5206 MONGOID-5235 broken_updates * MONGOID-5162 MONGOID-5234 object_id_as_json_oid * change to legacy_triple_equals * order options alphabetically Co-authored-by: Oleg Pudeyev <[email protected]>
1 parent 3f67ea4 commit 3a5329f

File tree

26 files changed

+368
-247
lines changed

26 files changed

+368
-247
lines changed

docs/reference/configuration.txt

Lines changed: 95 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,12 @@ for details on driver options.
252252
# Compressors to use. (default is to not use compression)
253253
compressors: [zlib]
254254

255-
# Configure Mongoid specific options. (optional)
255+
# Configure Mongoid-specific options. (optional)
256256
options:
257-
# Application name that is printed to the mongodb logs upon establishing
258-
# a connection in server versions >= 3.4. Note that the name cannot
259-
# exceed 128 bytes. It is also used as the database name if the
260-
# database name is not explicitly defined. (default: nil)
257+
# Application name that is printed to the MongoDB logs upon establishing
258+
# a connection in server versions 3.4 or greater. Note that the name
259+
# cannot exceed 128 bytes in length. It is also used as the database name
260+
# if the database name is not explicitly defined. (default: nil)
261261
app_name: MyApplicationName
262262

263263
# Create indexes in background by default. (default: false)
@@ -268,30 +268,34 @@ for details on driver options.
268268
# error. (default: true)
269269
belongs_to_required_by_default: true
270270

271-
# In Mongoid 7.3 and earlier, embedded matching performed time comparisons
272-
# with full (microsecond) precision. However, MongoDB server is only
273-
# capable of storing times with millisecond precision. Enabling this
274-
# option makes Mongoid truncate times to millisecond precision for
275-
# comparison purposes, to match the server behavior. (default: false)
276-
compare_time_by_ms: false
277-
278-
# Set the global discriminator key. (default: "_type")
279-
discriminator_key: "_type"
280-
281-
# Raise an exception when a field is redefined. (default: false)
282-
duplicate_fields_exception: false
283-
284-
# In Mongoid 7.3.3 and earlier, the pluck and distinct operations did
285-
# not respect aliased fields for embedded documents. Turning on this
286-
# flag changes those functions to recognize those aliases.
287-
# (default: false)
288-
fix_embedded_alias_pluck_distinct: false
289-
290-
# In Mongoid 7.3.3 and earlier, there was a bug when adding expressions
291-
# using the #and function. In certain situations, an $and clause would be
292-
# lost and replaced by one of the previous $and clauses. This would
293-
# happen when using the same operator on the same field multiple times.
294-
# For example:
271+
# Maintain broken behavior of sum over empty result sets for backwards
272+
# compatibility. When calculating a sum on a field with a null context,
273+
# for example:
274+
#
275+
# Product.none.sum(:price)
276+
#
277+
# ... return field name (`:price') instead of 0.
278+
#
279+
# When calculating a sum via a database query with an empty result set,
280+
# for example:
281+
#
282+
# Product.where(impossible_condition: true).sum(:price)
283+
#
284+
# ... return nil instead of 0.
285+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
286+
broken_aggregables: true
287+
288+
# Ignore aliased fields in embedded documents when performing pluck and
289+
# distinct operations, for backwards compatibility.
290+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
291+
broken_alias_handling: true
292+
293+
# Maintain broken `and' method behavior that existed in Mongoid 7.3
294+
# and earlier for backwards compatibility: in some situations, conditions
295+
# already present in a Criteria object would be replaced by newer
296+
# conditions when `and' method is used instead of the new conditions
297+
# being added to the existing conditions. This would happen when using
298+
# the same operator on the same field multiple times. For example:
295299
#
296300
# Band.where(id: 1).and({year: {'$in' => [2020]}}, {year: {'$in' => [2021]}}).where(id: 2)
297301
#
@@ -305,9 +309,53 @@ for details on driver options.
305309
#
306310
# This is obviously incorrect as the {"$in"=>[2021]} clause is lost.
307311
# Notice that the clause is only lost when both clauses are added using
308-
# the #and function. Turning on this feature flag fixes this bug.
309-
# (default: false)
310-
fix_multiple_ands: false
312+
# the #and method.
313+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
314+
broken_and: true
315+
316+
# When exiting a nested `with_scope' block, set the current scope to
317+
# nil instead of the parent scope for backwards compatibility.
318+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
319+
broken_scoping: true
320+
321+
# Maintain broken update behavior in some cases for backwards
322+
# compatibility.
323+
#
324+
# In Mongoid 7.3 and earlier, when assigning a value to an embedded
325+
# document, then setting it to nil, then assigning the original value
326+
# to it again, the second update would not work and the value for the
327+
# embedded document would remain nil. Take this case:
328+
#
329+
# canvas.palette = palette
330+
# canvas.palette = nil
331+
# canvas.palette = palette
332+
#
333+
# ... where canvas embeds_one palette.
334+
#
335+
# In Mongoid 7.3 and earlier, canvas.palette would be nil when we would
336+
# expect it to be palette. Set this option to true to keep this behavior,
337+
# set the option to false to perform the second update correctly.
338+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
339+
broken_updates: true
340+
341+
# Time objects in Ruby have nanosecond precision, whereas MongoDB server
342+
# can only store times with millisecond precision. Set this option to
343+
# true to truncate times to millisecond precision when performing
344+
# queries on already loaded embedded associations (this is also called
345+
# "embedded matching" and is done completely in Ruby), to obtain the
346+
# same query results when performing time comparisons regardless of
347+
# which documents are being queried. Setting this option to false will
348+
# produce different results for queries on embedded associations that
349+
# are already loaded into memory vs queries on unloaded associations and
350+
# top-level models. (default: false in Mongoid 7, will change to true
351+
# in Mongoid 8).
352+
compare_time_by_ms: false
353+
354+
# Set the global discriminator key. (default: "_type")
355+
discriminator_key: "_type"
356+
357+
# Raise an exception when a field is redefined. (default: false)
358+
duplicate_fields_exception: false
311359

312360
# Include the root model name in json serialization. (default: false)
313361
include_root_in_json: false
@@ -319,6 +367,15 @@ for details on driver options.
319367
# to parent contexts by default. (default: false)
320368
join_contexts: false
321369

370+
# Maintain legacy behavior of === on Mongoid document classes, which
371+
# returns true in a number of cases where Ruby's === implementation would
372+
# return false. Note that the behavior of === on Mongoid document
373+
# instances differs from both the behavior of === on document classes
374+
# and from Ruby's behavior of === on simple object instances regardless
375+
# of the value of this option.
376+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
377+
legacy_triple_equals: true
378+
322379
# Set the Mongoid and Ruby driver log levels when Mongoid is not using
323380
# Ruby on Rails logger instance. (default: :info)
324381
log_level: :info
@@ -327,6 +384,12 @@ for details on driver options.
327384
# as a BSON::Decimal128 instead of a string. (default: false)
328385
map_big_decimal_to_decimal128: false
329386

387+
# Force ``BSON::ObjectId#as_json`` method to return the hash
388+
# { "$oid" => id.to_s }. When this option is false, and bson-ruby 5
389+
# is used, the return value will be the hexadecimal ObjectId string only.
390+
# (default: true in Mongoid 7, will change to false in Mongoid 8)
391+
object_id_as_json_oid: true
392+
330393
# Preload all models in development, needed when models use
331394
# inheritance. (default: false)
332395
preload_models: false
@@ -335,59 +398,15 @@ for details on driver options.
335398
# (default: true)
336399
raise_not_found_error: true
337400

338-
# In Mongoid 7.3.3 and earlier, there was a bug when using with_scope
339-
# that after the function returned, any previous scopes were lost.
340-
# Turning this flag on fixes that bug. (default: false)
341-
restore_previous_scope: false
342-
343-
# In Mongoid 7.3.3 and earlier, when doing a sum on a field with a null
344-
# context, for example:
345-
#
346-
# Product.none.sum(:price)
347-
#
348-
# the sum incorrectly returned the field name as a Symbol. Turning on
349-
# this feature flag fixes this functionality to automatically return 0.
350-
# (default: false)
351-
return_zero_on_sum_none: false
352-
353401
# Raise an error when defining a scope with the same name as an
354402
# existing method. (default: false)
355403
scope_overwrite_exception: false
356404

357-
# Corrects === behavior to be consistent with Ruby by only calling is_a?
358-
# (default: false)
359-
triple_equals_uses_is_a: false
360-
361-
# In Mongoid 7.3.3 and earlier, when setting an embedded document, setting
362-
# it to nil, and then setting it again to that same original value, the
363-
# second update would not work and the value for the embedded document
364-
# would remain nil. Take this case:
365-
#
366-
# canvas.palette = palette
367-
# canvas.palette = nil
368-
# canvas.palette = palette
369-
# Where canvas embeds_one palette.
370-
#
371-
# In 7.3.3 and earlier, canvas.palette would be nil when we would expect
372-
# it to be palette. Since fixing this would be a breaking change, we have
373-
# put this fix behind this feature flag. Turning this flag on fixes this
374-
# bug, and canvas.palette would contain the correct value: the assigned
375-
# palette. (default: false)
376-
update_embedded_after_nil: false
377-
378405
# Use ActiveSupport's time zone in time operations instead of
379406
# the Ruby default time zone. See the time zone section below for
380407
# further information. (default: true)
381408
use_activesupport_time_zone: true
382409

383-
# In Mongoid 7.3.3 and earlier, the BSON::ObjectId#as_json method would
384-
# default to returning { "$oid" => id.to_s }. Turning on this flag will
385-
# defer the as_json call to bson-ruby's implementation of
386-
# BSON::ObjectId#as_json. In bson-ruby 5.x.x as_json will return
387-
# the id as a string. In bson-ruby 4.x.x as_json will return
388-
# { "$oid" => id.to_s }. (default: false)
389-
use_bson_ruby_as_json: false
390-
391410
# Return stored times as UTC. See the time zone section below for
392411
# further information. Most applications should not use this option.
393412
# (default: false)

docs/reference/queries.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,10 +1783,11 @@ at runtime:
17831783

17841784
.. note::
17851785

1786-
In Mongoid versions 7.3.3 and earlier, there is a bug in ``with_scope``
1787-
where the previous scope is lost after the function returns. Set the
1788-
``Mongoid.restore_previous_scope`` global flag to true in order to get the
1789-
correct functionality.
1786+
If with_scope calls are nested, when the nested with_scope block completes
1787+
Mongoid 7 sets the current scope to nil instead of the parent scope.
1788+
Mongoid 8 will set the current scope to the correct parent scope.
1789+
To get Mongoid 8 behavior in Mongoid 7.4 and higher, set the
1790+
``Mongoid.broken_scoping`` global option to false.
17901791

17911792

17921793
Class Methods

docs/release-notes/mongoid-7.4.txt

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ Previously, ``===`` returned ``true`` for some cases when the equivalent Ruby
4444

4545
.. note::
4646

47-
In order to get this functionality, the ``Mongoid.triple_equals_uses_is_a``
48-
global flag must be set to true. If it is set to false, the ``===`` operator
47+
In order to get this functionality, the ``Mongoid.legacy_triple_equals``
48+
global flag must be set to false. If it is set to true, the ``===`` operator
4949
will function as it did in Mongoid 7.3.
5050

5151
Mongoid 7.4 behavior:
@@ -103,25 +103,42 @@ and matches the core Ruby behavior:
103103
# => true
104104

105105

106-
``BSON::ObjectId#as_json`` Implementation Removed
107-
-------------------------------------------------
106+
``BSON::ObjectId#as_json`` Override Is Made Optional
107+
----------------------------------------------------
108108

109-
Mongoid in versions up to 7.3 used to provide a ``BSON::ObjectId#as_json``
109+
Mongoid 7.3 and earlier provided a ``BSON::ObjectId#as_json``
110110
implementation that was identical to the one provided by ``bson-ruby``.
111-
Mongoid 7.4 removes its copy of this implementation.
111+
Mongoid 7.4 adds an option to bypass its copy of this implementation,
112+
delegating to ``BSON::ObjectId#as_json``: ``Mongoid.object_id_as_json_oid``.
112113

113-
This change has no immediate impact on applications - ``BSON::ObjectId#as_json``
114-
behaves the same in Mongoid 7.4 as it did in Mongoid 7.3. However, if
115-
this implementation is changed in a future version of ``bson-ruby``
116-
which is `under consideration <https://jira.mongodb.org/browse/MONGOID-5158>`_,
117-
Mongoid 7.4 and later will inherit the new implementation provided by
118-
``bson-ruby`` while Mongoid 7.3 and earlier will continue with the
119-
implementation returning a hash of ``{"$oid" => "..."}``.
114+
When ``Mongoid.object_id_as_json_oid`` is set to ``true``, Mongoid will
115+
install an implementation of ``BSON::ObjectId#as_json`` which returns
116+
the hash ``{"$oid" => "..."}`` as it did in Mongoid 7.3 and earlier.
120117

121-
.. note::
118+
When ``Mongoid.object_id_as_json_oid`` is set to ``false``, Mongoid will
119+
delegate to ``bson-ruby`` implementation of ``BSON::ObjectId#as_json``, which
120+
in ``bson-ruby`` 4 continues to return the hash ``{"$oid" => "..."}`` but
121+
in ``bson-ruby`` 5 will return only the hexadecimal ObjectId string.
122+
123+
The behavior of ``as_json`` is summarized in the following table:
124+
125+
.. list-table::
126+
:header-rows: 1
127+
:stub-columns: 1
128+
:class: compatibility-large no-padding
129+
130+
* - ``Mongoid.object_id_as_json_oid`` value
131+
- true
132+
- false
133+
134+
* - ``bson-ruby`` 4
135+
- ``{"$oid"=>"621ed7fda15d5d231594627c"}``
136+
- ``{"$oid"=>"621ed7fda15d5d231594627c"}``
137+
138+
* - ``bson-ruby`` 5
139+
- ``{"$oid"=>"621ed7fda15d5d231594627c"}``
140+
- ``"621ed7fda15d5d231594627c"``
122141

123-
In order to get this functionality, the ``Mongoid.use_bson_ruby_as_json``
124-
feature flag must be turned on.
125142

126143
Scoped Associations
127144
-------------------

lib/mongoid/association/embedded/batchable.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ def batch_clear(docs)
3838
positionally(selector, "$unset" => { path => true }),
3939
session: _session
4040
)
41-
# This solves the case in which a user sets, clears and resets an
42-
# embedded document. Previously, since the embedded document was
43-
# already marked not a "new_record", it wouldn't be persisted to
44-
# the second time. This change fixes that and allows it to be persisted.
45-
docs.each { |doc| doc.new_record = true } if Mongoid.update_embedded_after_nil
41+
unless Mongoid.broken_updates
42+
# This solves the case in which a user sets, clears and resets an
43+
# embedded document. Previously, since the embedded document was
44+
# already marked not a "new_record", it wouldn't be persisted to
45+
# the second time. This change fixes that and allows it to be persisted.
46+
docs.each { |doc| doc.new_record = true }
47+
end
4648
post_process_batch_remove(docs, :delete)
4749
end
4850
_unscoped.clear

lib/mongoid/association/embedded/embeds_one/proxy.rb

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,30 @@ def substitute(replacement)
5454
# run the callbacks and state-changing code by passing persist: false in that case.
5555
_target.destroy(persist: !replacement) if persistable?
5656

57-
# A little explanation on why this is needed... Say we have three assignments:
58-
#
59-
# canvas.palette = palette
60-
# canvas.palette = nil
61-
# canvas.palette = palette
62-
# Where canvas embeds_one palette.
63-
#
64-
# Previously, what was happening was, on the first assignment,
65-
# palette was considered a "new record" (new_record?=true) and
66-
# thus palette was being inserted into the database. However,
67-
# on the third assignment, we're trying to reassign the palette,
68-
# palette is no longer considered a new record, because it had
69-
# been inserted previously. This is not exactly accurate,
70-
# because the second assignment ultimately removed the palette
71-
# from the database, so it needs to be reinserted. Since the
72-
# palette's new_record is false, Mongoid ends up "updating" the
73-
# document, which doesn't reinsert it into the database.
74-
#
75-
# The change I introduce here, respecifies palette as a "new
76-
# record" when it gets removed from the database, so if it is
77-
# reassigned, it will be reinserted into the database.
78-
_target.new_record = true if Mongoid.update_embedded_after_nil
57+
unless Mongoid.broken_updates
58+
# A little explanation on why this is needed... Say we have three assignments:
59+
#
60+
# canvas.palette = palette
61+
# canvas.palette = nil
62+
# canvas.palette = palette
63+
# Where canvas embeds_one palette.
64+
#
65+
# Previously, what was happening was, on the first assignment,
66+
# palette was considered a "new record" (new_record?=true) and
67+
# thus palette was being inserted into the database. However,
68+
# on the third assignment, we're trying to reassign the palette,
69+
# palette is no longer considered a new record, because it had
70+
# been inserted previously. This is not exactly accurate,
71+
# because the second assignment ultimately removed the palette
72+
# from the database, so it needs to be reinserted. Since the
73+
# palette's new_record is false, Mongoid ends up "updating" the
74+
# document, which doesn't reinsert it into the database.
75+
#
76+
# The change I introduce here, respecifies palette as a "new
77+
# record" when it gets removed from the database, so if it is
78+
# reassigned, it will be reinserted into the database.
79+
_target.new_record = true
80+
end
7981
end
8082
unbind_one
8183
return nil unless replacement

0 commit comments

Comments
 (0)