@@ -28,17 +28,14 @@ Field type definitions determine how Mongoid behaves when constructing queries
2828and retrieving/writing fields from/to the database. Specifically:
2929
30301. When assigning values to fields at runtime, the values are converted to the
31- specified type.
32-
31+ specified type.
33322. 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.
37353. 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.
40374. When retrieving documents from the database, field values are converted
41- to the specified type.
38+ to the specified type.
4239
4340Changing the field definitions in a model class does not alter data already stored in
4441MongoDB. To update type or contents of fields of existing documents,
@@ -63,25 +60,26 @@ on a person by using the ``field`` macro.
6360The 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
8785Mongoid 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
447471This is because the meaning of ``$`` is different between PCRE and Ruby
448472regular expressions.
449473
450- .. _bigdecimal-fields :
474+ .. _field-type-big-decimal :
451475
452476BigDecimal 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
894927Reading Uncastable Values
895928`````````````````````````
@@ -1094,11 +1127,25 @@ The ``demongoize`` method is used when calling the getters of fields for your cu
10941127Note 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
11031150Lastly, the class method ``evolve`` is similar to ``mongoize``, however it is used
11041151when 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
11751227You may define custom options for the ``field`` macro function
11761228which 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
11791231validator for the field. First, declare the new field option in an initializer,
11801232specifiying 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
11901242Then, 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
12001252Note 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
13751427By 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>`_
0 commit comments