Skip to content

Commit 21d7fcd

Browse files
committed
Improve docs primarily for the "Fields" page, as well as a few small things for clarity in various places.
This also adds documentation for previously undocumented "Custom Field Options" functionality (Mongoid::Fields.option)
1 parent 0a7cf5a commit 21d7fcd

File tree

4 files changed

+144
-85
lines changed

4 files changed

+144
-85
lines changed

docs/reference/fields.txt

Lines changed: 132 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ Field Definition
1313
:class: singlecol
1414

1515

16+
.. _field-types:
17+
1618
Field Types
1719
===========
1820

19-
Even though MongoDB is a schemaless database and allows data to be stored
20-
as strings, Mongoid permits the application to declare the type of data
21-
stored in the various fields of a document. Field type declarations affect
22-
the following:
21+
MongoDB stores underlying document data using
22+
`BSON types <https://docs.mongodb.com/manual/reference/bson-types/>`_, and
23+
Mongoid converts BSON types to Ruby types at runtime in your application.
24+
For example, a field defined with `type: :float` will use the Ruby ``Float``
25+
class in-memory and will persist in the database as the the BSON ``double`` type.
26+
27+
Field type definitions determine how Mongoid behaves when constructing queries
28+
and retrieving/writing fields from/to the database. Specifically:
2329

24-
1. When assigning values to fields, the values are converted to the
30+
1. When assigning values to fields at runtime, the values are converted to the
2531
specified type.
2632

2733
2. When persisting data to MongoDB, the data is sent in an appropriate
@@ -34,26 +40,24 @@ type before being sent to MongoDB.
3440
4. When retrieving documents from the database, field values are converted
3541
to the specified type.
3642

37-
Field type definitions determine how Mongoid behaves when constructing the
38-
queries, retrieving and writing fields from the database. Changing the field
39-
definitions in a model class does not alter data already stored in
43+
Changing the field definitions in a model class does not alter data already stored in
4044
MongoDB. To update type or contents of fields of existing documents,
4145
the field must be re-saved to the database. Note that, due to Mongoid
4246
tracking which attributes on a model change and only saving the changed ones,
4347
it may be necessary to explicitly write a field value when changing the
4448
type of an existing field without changing the stored values.
4549

4650
Consider a simple class for modeling a person in an application. A person may
47-
have a first name, last name, and middle name. We can define these attributes
51+
have a name, date_of_birth, and weight. We can define these attributes
4852
on a person by using the ``field`` macro.
4953

5054
.. code-block:: ruby
5155

5256
class Person
5357
include Mongoid::Document
54-
field :first_name, type: String
55-
field :middle_name, type: String
56-
field :last_name, type: String
58+
field :name, type: String
59+
field :date_of_birth, type: Date
60+
field :weight, type: Float
5761
end
5862

5963
Below is a list of valid types for fields.
@@ -77,6 +81,14 @@ Below is a list of valid types for fields.
7781
- ``Time``
7882
- ``TimeWithZone``
7983

84+
To define custom field types, refer to :ref:`Custom Field Types <custom-field-types>` below.
85+
86+
87+
.. _omitting-field-type-definition:
88+
89+
Omitting Field Type Definition
90+
------------------------------
91+
8092
If you decide not to specify the type of field with the definition, Mongoid will treat
8193
it as an object and not try to typecast it when sending the values to the database.
8294
This can be advantageous as the lack of attempted conversion will yield a slight
@@ -103,15 +115,15 @@ Types that are not supported as dynamic attributes since they cannot be cast are
103115
- ``Range``
104116

105117

106-
.. _stringified-symbol:
118+
.. _field-type-stringified-symbol:
107119

108-
The StringifiedSymbol Type
109-
--------------------------
120+
Field Type: StringifiedSymbol
121+
-----------------------------
110122

111123
The ``StringifiedSymbol`` field type is the recommended field type for storing
112124
values that should be exposed as symbols to Ruby applications. When using the ``Symbol`` field type,
113125
Mongoid defaults to storing values as BSON symbols. For more information on the
114-
BSON symbol type, see :ref:`here <bson-symbol>`.
126+
BSON symbol type, see :ref:`here <field-type-symbol>`.
115127
However, the BSON symbol type is deprecated and is difficult to work with in programming languages
116128
without native symbol types, so the ``StringifiedSymbol`` type allows the use of symbols
117129
while ensuring interoperability with other drivers. The ``StringifiedSymbol`` type stores all data
@@ -157,12 +169,12 @@ migration from fields that currently store either strings or BSON symbols in the
157169
``StringifiedSymbol`` field type.
158170

159171

160-
.. _bson-symbol:
172+
.. _field-type-symbol:
161173

162-
BSON Symbol Type
163-
----------------
174+
Field Type: Symbol
175+
------------------
164176

165-
New applications should use the :ref:`StringifiedSymbol field type <stringified-symbol>`
177+
New applications should use the :ref:`StringifiedSymbol field type <field-type-stringified-symbol>`
166178
to store Ruby symbols in the database. The ``StringifiedSymbol`` field type
167179
provides maximum compatibility with other applications and programming languages
168180
and has the same behavior in all circumstances.
@@ -188,8 +200,10 @@ snippet in your project:
188200
end
189201

190202

191-
Hash Fields
192-
-----------
203+
.. _field-type-hash:
204+
205+
Field Type: Hash
206+
----------------
193207

194208
When using a field of type Hash, be wary of adhering to the
195209
`legal key names for mongoDB <http://docs.mongodb.org/manual/reference/limits/#naming-restrictions>`_,
@@ -218,8 +232,10 @@ or else the values will not store properly.
218232
end
219233

220234

221-
Time Fields
222-
-----------
235+
.. _field-type-time:
236+
237+
Field Type: Time
238+
----------------
223239

224240
``Time`` fields store values as ``Time`` instances in the :ref:`configured
225241
time zone <time-zones>`.
@@ -242,8 +258,10 @@ In the above example, the value was interpreted as the beginning of today in
242258
local time, because the application was not configured to use UTC times.
243259

244260

245-
Date Fields
246-
-----------
261+
.. _field-type-date:
262+
263+
Field Type: Date
264+
----------------
247265

248266
Mongoid allows assignment of values of several types to ``Date`` fields:
249267

@@ -265,8 +283,11 @@ recommended to explicitly convert ``String``, ``Time`` and ``DateTime``
265283
objects to ``Date`` objects before assigning the values to fields of type
266284
``Date``.
267285

268-
DateTime Fields
269-
---------------
286+
287+
.. _field-type-date-time:
288+
289+
Field Type: DateTime
290+
---------------------
270291

271292
MongoDB stores all times as UTC timestamps. When assigning a value to a
272293
``DateTime`` field, or when querying a ``DateTime`` field, Mongoid
@@ -332,13 +353,13 @@ If a time zone is specified, it is respected:
332353
# => Sun, 04 Mar 2018 09:00:00 +0000
333354

334355

335-
.. _regular-expression-fields:
356+
.. _field-type-regexp:
336357

337-
Regular Expression Fields
338-
-------------------------
358+
Field Type: Regexp
359+
------------------
339360

340361
MongoDB supports storing regular expressions in documents, and querying using
341-
regular expressions. Of note for Ruby applications, MongoDB uses
362+
regular expressions. Note that MongoDB uses
342363
`Perl-compatible regular expressions (PCRE) <http://pcre.org/>`_
343364
and Ruby uses `Onigmo <https://github.com/k-takata/Onigmo>`_, which is a
344365
fork of `Oniguruma regular expression engine <https://github.com/kkos/oniguruma>`_.
@@ -396,8 +417,10 @@ This is because the meaning of ``$`` is different between PCRE and Ruby
396417
regular expressions.
397418

398419

399-
Defaults
400-
--------
420+
.. _field-default-values:
421+
422+
Specifying Field Default Values
423+
-------------------------------
401424

402425
A field can be configured to have a default value. The default value can be
403426
fixed, as in the following example:
@@ -587,7 +610,7 @@ To define the field anyway, use the ``overwrite: true`` option:
587610

588611
.. _custom-id:
589612

590-
Custom Ids
613+
Custom IDs
591614
----------
592615

593616
By default, Mongoid defines the ``_id`` field on documents to contain a
@@ -640,16 +663,20 @@ alias can :ref:`be removed <unalias-id>` if desired (such as to integrate
640663
with systems that use the ``id`` field to store value different from ``_id``.
641664

642665

666+
.. _customizing-field-behavior:
667+
643668
Customizing Field Behavior
644669
==========================
645670

646-
Mongoid offers several options for customizing the behavior of fields.
671+
Mongoid offers several ways to customize the behavior of fields.
647672

648673

674+
.. _custom-getters-and-setters:
675+
649676
Custom Getters And Setters
650677
--------------------------
651678

652-
You can define custom getters and setters for fields to modify the values
679+
You may override getters and setters for fields to modify the values
653680
when they are being accessed or written. The getters and setters use the
654681
same name as the field. Use ``read_attribute`` and ``write_attribute``
655682
methods inside the getters and setters to operate on the raw attribute
@@ -707,12 +734,14 @@ may be implemented as follows:
707734
# => {"_id"=>BSON::ObjectId('613fa15aa15d5d617216104c'), "value"=>2.0, "unit"=>nil}
708735

709736

737+
.. _custom-field-types:
738+
710739
Custom Field Types
711740
------------------
712741

713742
You can define custom types in Mongoid and determine how they are serialized
714-
and deserialized. You simply need to provide three methods on it for Mongoid
715-
to call to convert your object to and from MongoDB friendly values.
743+
and deserialized. In this example, we define a new field type ``Point``, which we
744+
can use in our model class as follows:
716745

717746
.. code-block:: ruby
718747

@@ -721,6 +750,11 @@ to call to convert your object to and from MongoDB friendly values.
721750
field :location, type: Point
722751
end
723752

753+
Then make a Ruby class to represent the type. This class must define methods
754+
used for MongoDB serialization and deserialization as follows:
755+
756+
.. code-block:: ruby
757+
724758
class Point
725759

726760
attr_reader :x, :y
@@ -730,18 +764,13 @@ to call to convert your object to and from MongoDB friendly values.
730764
end
731765

732766
# Converts an object of this instance into a database friendly value.
767+
# In this example, we store the values in the database as array.
733768
def mongoize
734769
[ x, y ]
735770
end
736771

737772
class << self
738773

739-
# Get the object as it was stored in the database, and instantiate
740-
# this custom class from it.
741-
def demongoize(object)
742-
Point.new(object[0], object[1])
743-
end
744-
745774
# Takes any possible object and converts it to how it would be
746775
# stored in the database.
747776
def mongoize(object)
@@ -752,8 +781,14 @@ to call to convert your object to and from MongoDB friendly values.
752781
end
753782
end
754783

784+
# Get the object as it was stored in the database, and instantiate
785+
# this custom class from it.
786+
def demongoize(object)
787+
Point.new(object[0], object[1])
788+
end
789+
755790
# Converts the object that was supplied to a criteria and converts it
756-
# into a database friendly form.
791+
# into a query-friendly form.
757792
def evolve(object)
758793
case object
759794
when Point then object.mongoize
@@ -763,42 +798,69 @@ to call to convert your object to and from MongoDB friendly values.
763798
end
764799
end
765800

766-
The instance method ``mongoize`` takes an instance of your object, and
767-
converts it into how it will be stored in the database. In our example above,
768-
we want to store our point object as an array in the form ``[ x, y ]``.
801+
The instance method ``mongoize`` takes an instance of your custom type object, and
802+
converts it into a represenation of how it will be stored in the database, i.e. to pass
803+
to the MongoDB Ruby driver. In our example above, we want to store our ``Point``
804+
object as an ``Array`` in the form ``[ x, y ]``.
769805

770-
The class method ``demongoize`` takes an object as how it was stored in the
771-
database, and is responsible for instantiating an object of your custom type.
772-
In this case, we take an array and instantiate a ``Point`` from it.
773-
774-
The class method ``mongoize`` takes an object that you would use to set on
775-
your model from your application code, and create the object as it would be
776-
stored in the database. This is for cases where you are not passing your
777-
model instances of your custom type in the setter:
806+
The class method ``mongoize`` is similar to the instance method, however it must handle
807+
objects of all possible types as inputs. The ``mongoize`` method is used when calling the
808+
setter methods for fields of your custom type.
778809

779810
.. code-block:: ruby
780811

781812
point = Point.new(12, 24)
782-
venue = Venue.new(location: point) # This uses the mongoize instance method.
783-
venue = Venue.new(location: [ 12, 24 ]) # This uses the mongoize class method.
813+
venue = Venue.new(location: point) # This uses the Point#mongoize instance method.
814+
venue = Venue.new(location: [ 12, 24 ]) # This uses the Point.mongoize class method.
815+
816+
The class method ``demongoize`` does the inverse of ``mongoize``. It takes the raw object
817+
from the MongoDB Ruby driver and converts it to an instance of your custom type.
818+
In this case, the database driver returns an ``Array`` and we instantiate a ``Point`` from it.
819+
The ``demongoize`` method is used when calling the getters of fields for your custom type.
820+
Note that in the example above, since ``demongoize`` calls ``Point.new``, a new instance of
821+
``Point`` will be generated on each call to the getter.
784822

785-
The class method ``evolve`` takes an object, and determines how it is to be
786-
transformed for use in criteria. For example we may want to write a query
787-
like so:
823+
Lastly, the class method ``evolve`` is similar to ``mongoize``, however it is used
824+
when transforming objects for use in Mongoid query criteria.
788825

789826
.. code-block:: ruby
790827

791828
point = Point.new(12, 24)
792-
Venue.where(location: point)
829+
Venue.where(location: point) # This uses Point.evolve
830+
831+
832+
.. _custom-field-options:
833+
834+
Custom Field Options
835+
--------------------
793836

794-
Note that when accessing custom fields from the document, you will get a
795-
new instance of that object with each call to the getter. This is because
796-
Mongoid is generating a new object from the raw attributes on each access.
837+
You may define custom options for the ``field`` macro function
838+
which extend its behavior at the your time model classes are loaded.
839+
840+
As an example, we will define a ``:required`` option which will add a presence
841+
validator for the field. First, declare the new field option in an initializer,
842+
specifiying its handler function as a block:
843+
844+
.. code-block:: ruby
845+
846+
# in /config/initializers/mongoid_custom_fields.rb
847+
848+
Mongoid::Fields.option :required do |model, field, value|
849+
model.validates_presence_of field if value
850+
end
851+
852+
Then, use it your model class:
853+
854+
.. code-block:: ruby
855+
856+
class Person
857+
include Mongoid::Document
858+
859+
field :name, type: String, required: true
860+
end
797861

798-
We need the point object in the criteria to be transformed to a
799-
MongoDB-friendly value when it is not as well, ``evolve`` is the method
800-
that takes care of this. We check if the passed in object is a ``Point``
801-
first, in case we also want to be able to pass in ordinary arrays instead.
862+
Note that the handler function will be invoked whenever the option is used
863+
in the field definition, even if the option's value is false or nil.
802864

803865

804866
.. _dynamic-fields:

0 commit comments

Comments
 (0)