Skip to content

Commit 8394a97

Browse files
Merge branch 'master' into uncastable-value
2 parents e9d314b + a189655 commit 8394a97

34 files changed

+776
-136
lines changed

docs/reference/crud.txt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,15 +320,13 @@ Mongoid provides the following persistence-related attributes:
320320
person.persisted? # => true
321321

322322

323-
324323
Atomic
325324
------
326325

327-
Although Mongoid performs atomic operations under the covers by default,
328-
there may be cases where you want to do this explicitly without persisting
329-
other fields. Mongoid provides support for all of these operations as well.
330-
When executing atomic operations via these methods, callbacks and validations
331-
are not invoked.
326+
Mongoid exposes :manual:`MongoDB update operators </reference/operator/update/>`
327+
as methods on Mongoid documents. When these methods are used, callbacks are
328+
not invoked and validations are not performed. The supported update operators
329+
are:
332330

333331
.. list-table::
334332
:header-rows: 1
@@ -472,6 +470,12 @@ are not invoked.
472470

473471
person.unset(:name)
474472

473+
Note that, because these methods skip validations, it is possible to both
474+
save invalid documents into the database and end up with invalid documents
475+
in the application (which would subsequently fail to save via a ``save``
476+
call due to the failing validations).
477+
478+
475479
.. _atomic-operation-grouping:
476480

477481
Atomic Operation Grouping

docs/reference/fields.txt

Lines changed: 149 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,14 @@ Field type definitions determine how Mongoid behaves when constructing queries
2828
and retrieving/writing fields from/to the database. Specifically:
2929

3030
1. When assigning values to fields at runtime, the values are converted to the
31-
specified type.
32-
31+
specified type.
3332
2. When persisting data to MongoDB, the data is sent in an appropriate
34-
type, permitting richer data manipulation within MongoDB or by other
35-
tools.
36-
33+
type, permitting richer data manipulation within MongoDB or by other
34+
tools.
3735
3. When querying documents, query parameters are converted to the specified
38-
type before being sent to MongoDB.
39-
36+
type before being sent to MongoDB.
4037
4. When retrieving documents from the database, field values are converted
41-
to the specified type.
38+
to the specified type.
4239

4340
Changing the field definitions in a model class does not alter data already stored in
4441
MongoDB. To update type or contents of fields of existing documents,
@@ -63,25 +60,26 @@ on a person by using the ``field`` macro.
6360
The valid types for fields are as follows:
6461

6562
- ``Array``
66-
- ``BigDecimal``
63+
- ``BSON::Binary``
64+
- :ref:`BigDecimal <field-type-big-decimal>`
6765
- ``Mongoid::Boolean``, which may be specified simply as ``Boolean`` in the
6866
scope of a class which included ``Mongoid::Document``.
69-
- ``Date``
70-
- ``DateTime``
67+
- :ref:`Date <field-type-date>`
68+
- :ref:`DateTime <field-type-date-time>`
7169
- ``Float``
72-
- ``Hash``
70+
- :ref:`Hash <field-type-hash>`
7371
- ``Integer``
72+
- :ref:`Object <untyped-fields>`
7473
- ``BSON::ObjectId``
75-
- ``BSON::Binary``
7674
- ``Range``
77-
- ``Regexp``
75+
- :ref:`Regexp <field-type-regexp>`
7876
- ``Set``
7977
- ``String``
80-
- ``Mongoid::StringifiedSymbol``, which may be specified simply as
81-
``StringifiedSymbol`` in the scope of a class which included
82-
``Mongoid::Document``.
83-
- ``Symbol``
84-
- ``Time``
78+
- :ref:`Mongoid::StringifiedSymbol <field-type-stringified-symbol>`,
79+
which may be specified simply as ``StringifiedSymbol`` in the scope of a
80+
class which included ``Mongoid::Document``.
81+
- :ref:`Symbol <field-type-stringified-symbol>`
82+
- :ref:`Time <field-type-time>`
8583
- ``ActiveSupport::TimeWithZone``
8684

8785
Mongoid also recognizes the string ``"Boolean"`` as an alias for the
@@ -97,34 +95,60 @@ To define custom field types, refer to :ref:`Custom Field Types <custom-field-ty
9795
``BSON::Decimal128`` will return values of type ``BSON::Decimal128`` in
9896
BSON <=4 and values of type ``BigDecimal`` in BSON 5+.
9997

100-
.. _omitting-field-type-definition:
10198

102-
Omitting Field Type Definition
103-
------------------------------
99+
.. _untyped-fields:
104100

105-
If you decide not to specify the type of field with the definition, Mongoid will treat
106-
it as an object and not try to typecast it when sending the values to the database.
107-
This can be advantageous as the lack of attempted conversion will yield a slight
108-
performance gain. However some types are not supported if not defined as fields.
109-
You can safely omit type specifications when:
101+
Untyped Fields
102+
--------------
110103

111-
- You're not using a web front end and values are already properly cast.
112-
- All of your fields are strings.
104+
Not specifying a type for a field is the same as specifying the ``Object``
105+
type. Such fields are untyped:
113106

114107
.. code-block:: ruby
115108

116-
class Person
117-
include Mongoid::Document
118-
field :first_name
119-
field :middle_name
120-
field :last_name
121-
end
109+
class Product
110+
include Mongoid::Document
122111

123-
Types that are not supported as dynamic attributes since they cannot be cast are:
112+
field :properties
113+
# Equivalent to:
114+
field :properties, type: Object
115+
end
124116

125-
- ``Date``
126-
- ``DateTime``
127-
- ``Range``
117+
An untyped field can store values of any type which is directly serializable
118+
to BSON. This is useful when a field may contain values of different types
119+
(i.e. it is a variant type field), or when the type of values is not known
120+
ahead of time:
121+
122+
.. code-block:: ruby
123+
124+
product = Product.new(properties: "color=white,size=large")
125+
product.properties
126+
# => "color=white,size=large"
127+
128+
product = Product.new(properties: {color: "white", size: "large"})
129+
product.properties
130+
# => {:color=>"white", :size=>"large"}
131+
132+
When values are assigned to the field, Mongoid still performs mongoization but
133+
uses the class of the value rather than the field type for mongoization logic.
134+
135+
.. code-block:: ruby
136+
137+
product = Product.new(properties: 0..10)
138+
product.properties
139+
# The range 0..10, mongoized:
140+
# => {"min"=>0, "max"=>10}
141+
142+
When reading data from the database, Mongoid does not perform any type
143+
conversions on untyped fields. For this reason, even though it is possible
144+
to write any BSON-serializable value into an untyped fields, values which
145+
require special handling on the database reading side will generally not work
146+
correctly in an untyped field. Among field types supported by Mongoid,
147+
values of the following types should not be stored in untyped fields:
148+
149+
- ``Date`` (values will be returned as ``Time``)
150+
- ``DateTime`` (values will be returned as ``Time``)
151+
- ``Range`` (values will be returned as ``Hash``)
128152

129153

130154
.. _field-type-stringified-symbol:
@@ -447,7 +471,7 @@ matches strings containing "hello" before a newline, besides strings ending in
447471
This is because the meaning of ``$`` is different between PCRE and Ruby
448472
regular expressions.
449473

450-
.. _bigdecimal-fields:
474+
.. _field-type-big-decimal:
451475

452476
BigDecimal Fields
453477
-----------------
@@ -890,6 +914,15 @@ Note that the original uncastable values will be stored in the
890914
user.attributes_before_type_cast["name"]
891915
# => ["Mike", "Trout"]
892916

917+
.. note::
918+
919+
Note that for numeric fields, any class that defines ``to_i`` for Integer
920+
fields, ``to_f`` for Floats, and ``to_d`` for BigDecimals, is castable.
921+
Strings are the exception and will only call the corresponding ``to_*``
922+
method if the string is numeric. If a class only defines ``to_i`` and not
923+
``to_f`` and is being assigned to a Float field, this is uncastable, and Mongoid
924+
will not perform a two-step conversion (i.e. ``to_i`` and then ``to_f``).
925+
893926

894927
Reading Uncastable Values
895928
`````````````````````````
@@ -1094,11 +1127,25 @@ The ``demongoize`` method is used when calling the getters of fields for your cu
10941127
Note that in the example above, since ``demongoize`` calls ``Point.new``, a new instance of
10951128
``Point`` will be generated on each call to the getter.
10961129

1097-
.. note::
1130+
Mongoid will always call the ``demongoize`` method on values that were
1131+
retrieved from the database, but applications may, in theory, call
1132+
``demongoize`` with arbitrary input. It is recommended that applications add
1133+
handling for arbitrary input in their ``demongoize`` methods. We can rewrite
1134+
``Point``'s demongoize method as follows:
10981135

1099-
The ``mongoize`` and ``demongoize`` methods should return ``nil`` on values
1100-
that are uncastable to your custom type. See the section on :ref:`Uncastable
1101-
Values <uncastable-values>` for more details.
1136+
.. code:: ruby
1137+
1138+
def demongoize(object)
1139+
if object.is_a?(Array) && object.length == 2
1140+
Point.new(object[0], object[1])
1141+
end
1142+
end
1143+
1144+
Notice that ``demongoize`` will only create a new ``Point`` if given an array
1145+
of length 2, and will return ``nil`` otherwise. Both the ``mongoize`` and
1146+
``demongoize`` methods should be prepared to receive arbitrary input and should
1147+
return ``nil`` on values that are uncastable to your custom type. See the
1148+
section on :ref:`Uncastable Values <uncastable-values>` for more details.
11021149

11031150
Lastly, the class method ``evolve`` is similar to ``mongoize``, however it is used
11041151
when transforming objects for use in Mongoid query criteria.
@@ -1108,6 +1155,11 @@ when transforming objects for use in Mongoid query criteria.
11081155
point = Point.new(12, 24)
11091156
Venue.where(location: point) # This uses Point.evolve
11101157

1158+
The ``evolve`` method should also be prepared to receive arbitrary input,
1159+
however, unlike the ``mongoize`` and ``demongoize`` methods, it should return
1160+
the inputted value on values that are uncastable to your custom type. See the
1161+
section on :ref:`Uncastable Values <uncastable-values>` for more details.
1162+
11111163

11121164
.. _phantom-custom-field-types:
11131165

@@ -1175,16 +1227,16 @@ Custom Field Options
11751227
You may define custom options for the ``field`` macro function
11761228
which extend its behavior at the your time model classes are loaded.
11771229

1178-
As an example, we will define a ``:required`` option which will add a presence
1230+
As an example, we will define a ``:max_length`` option which will add a length
11791231
validator for the field. First, declare the new field option in an initializer,
11801232
specifiying its handler function as a block:
11811233

11821234
.. code-block:: ruby
11831235

11841236
# in /config/initializers/mongoid_custom_fields.rb
11851237

1186-
Mongoid::Fields.option :required do |model, field, value|
1187-
model.validates_presence_of field if value
1238+
Mongoid::Fields.option :max_length do |model, field, value|
1239+
model.validates_length_of field.name, maximum: value
11881240
end
11891241

11901242
Then, use it your model class:
@@ -1194,7 +1246,7 @@ Then, use it your model class:
11941246
class Person
11951247
include Mongoid::Document
11961248

1197-
field :name, type: String, required: true
1249+
field :name, type: String, max_length: 10
11981250
end
11991251

12001252
Note that the handler function will be invoked whenever the option is used
@@ -1369,7 +1421,7 @@ Mongoid supports localized fields via `i18n <https://github.com/ruby-i18n/i18n>`
13691421

13701422
class Product
13711423
include Mongoid::Document
1372-
field :description, localize: true
1424+
field :description, type: String, localize: true
13731425
end
13741426

13751427
By telling the field to ``localize``, Mongoid will under the covers store the field
@@ -1395,6 +1447,36 @@ You can get and set all the translations at once by using the corresponding ``_t
13951447
product.description_translations =
13961448
{ "en" => "Marvelous!", "de" => "Wunderbar!" }
13971449

1450+
Localized fields can be used with any field type. For example, they can be used
1451+
with float fields for differences with currency:
1452+
1453+
.. code:: ruby
1454+
1455+
class Product
1456+
include Mongoid::Document
1457+
1458+
field :price, type: Float, localize: true
1459+
field :currency, type: String, localize: true
1460+
end
1461+
1462+
By creating the model in this way, we can separate the price from the currency
1463+
type, which allows you to use all of the number-related functionalities on the
1464+
price when querying or aggregating that field (provided that you index into the
1465+
stored translations hash). We can create an instance of this model as follows:
1466+
1467+
.. code:: ruby
1468+
1469+
product = Product.new
1470+
I18n.locale = :en
1471+
product.price = 1.00
1472+
product.currency = "$"
1473+
I18n.locale = :he
1474+
product.price = 3.24
1475+
product.currency = "₪"
1476+
1477+
product.attributes
1478+
# => { "price" => { "en" => 1.0, "he" => 3.24 }, "currency" => { "en" => "$", "he" => "₪" } }
1479+
13981480

13991481
.. _present-fields:
14001482

@@ -1469,6 +1551,24 @@ language, translations will be looked up in the fallback languages:
14691551
I18n.locale = :de
14701552
product.description # "Marvelous!"
14711553

1554+
Mongoid also defines a ``:fallbacks`` option on fields, which can be used to
1555+
disable fallback functionality on a specific field:
1556+
1557+
.. code:: ruby
1558+
1559+
class Product
1560+
include Mongoid::Document
1561+
field :description, type: String, localize: true, fallbacks: false
1562+
end
1563+
1564+
product = Product.new
1565+
I18n.locale = :en
1566+
product.description = "Marvelous!"
1567+
I18n.locale = :de
1568+
product.description # nil
1569+
1570+
Note that this option defaults to ``true``.
1571+
14721572
.. note::
14731573

14741574
In i18n 1.1, the behavior of fallbacks `changed <https://github.com/ruby-i18n/i18n/pull/415>`_

docs/reference/inheritance.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ Inheritance
1212
:depth: 2
1313
:class: singlecol
1414

15+
16+
.. _inheritance-overview:
17+
18+
Overview
19+
========
20+
1521
Mongoid supports inheritance in both top level and embedded documents. When
1622
a child document inherits from a parent document, the parent document's
1723
fields, associations, validations and scopes are copied to the child document.

docs/release-notes/mongoid-7.5.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,31 @@ Mongoid 8 will require Ruby 2.6 or newer, JRuby 9.3 or newer and Rails 5.2 or
2626
newer.
2727

2828

29+
Feature Flags Summary
30+
---------------------
31+
32+
To ensure a stable upgrade path from Mongoid 7.4, Mongoid 7.5
33+
introduces feature flags which are further explained in the
34+
sections below.
35+
36+
To enable all new behavior in Mongoid 7.5, please use the following
37+
:ref:`configuration options <configuration-options>` in your mongoid.yml file.
38+
We recommend newly created apps to do this as well.
39+
40+
.. code-block:: yaml
41+
42+
development:
43+
...
44+
options:
45+
# Enable all new behavior in Mongoid 7.5
46+
legacy_attributes: false
47+
overwrite_chained_operators: false
48+
49+
In addition, please refer to the release notes of earlier 7.x versions for
50+
feature flags introduced in each version. For clarity, Mongoid 7.5 does
51+
not switch the behavior of any previously introduced feature flag.
52+
53+
2954
Implemented ``Criteria#take/take!`` Method
3055
------------------------------------------
3156

0 commit comments

Comments
 (0)