Skip to content

Commit 22222c6

Browse files
committed
- Prefer defining field type value as a Symbol rather than a Class. (Symbol is already supported today.)
- Deprecate using field type as a Class. - Add ability to define custom field types using a mini DSL (Mongoid::Fields.configure) - Fix Mongoid::Fields.option documentation
1 parent eb1c9bb commit 22222c6

File tree

10 files changed

+535
-148
lines changed

10 files changed

+535
-148
lines changed

docs/reference/fields.txt

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -55,34 +55,40 @@ on a person by using the ``field`` macro.
5555

5656
class Person
5757
include Mongoid::Document
58-
field :name, type: String
59-
field :date_of_birth, type: Date
60-
field :weight, type: Float
58+
field :name, type: :string
59+
field :date_of_birth, type: :date
60+
field :weight, type: :float
6161
end
6262

6363
Below is a list of valid types for fields.
6464

65-
- ``Array``
66-
- ``BigDecimal``
67-
- ``Boolean``
68-
- ``Date``
69-
- ``DateTime``
70-
- ``Float``
71-
- ``Hash``
72-
- ``Integer``
73-
- ``BSON::ObjectId``
74-
- ``BSON::Binary``
75-
- ``Range``
76-
- ``Regexp``
77-
- ``Set``
78-
- ``String``
79-
- ``StringifiedSymbol``
80-
- ``Symbol``
81-
- ``Time``
82-
- ``TimeWithZone``
65+
- ``:array``
66+
- ``:big_decimal``
67+
- ``:boolean``
68+
- ``:date``
69+
- ``:date_time``
70+
- ``:decimal128`` (uses ``BSON::Decimal128``)
71+
- ``:float``
72+
- ``:hash``
73+
- ``:integer``
74+
- ``:object_id`` (uses ``BSON::ObjectID``)
75+
- ``:binary`` (uses ``BSON::Binary``)
76+
- ``:range``
77+
- ``:regexp``
78+
- ``:set``
79+
- ``:string``
80+
- ``:stringified_symbol`` (see below)
81+
- ``:symbol``
82+
- ``:time``
83+
- ``:time_with_zone``
8384

8485
To define custom field types, refer to :ref:`Custom Field Types <custom-field-types>` below.
8586

87+
As of Mongoid 8.0, ``field :type`` should be specified as a ``Symbol``.
88+
Specifying as a ``Class`` is deprecated and will be no longer supported in a
89+
future major version of Mongoid. Unrecognized field type symbols will result
90+
in an `InvalidFieldType` error when the model class is loaded.
91+
8692

8793
.. _omitting-field-type-definition:
8894

@@ -116,16 +122,16 @@ Types that are not supported as dynamic attributes since they cannot be cast are
116122

117123
.. _field-type-stringified-symbol:
118124

119-
Field Type: StringifiedSymbol
120-
-----------------------------
125+
Field Type :stringified_symbol
126+
------------------------------
121127

122-
The ``StringifiedSymbol`` field type is the recommended field type for storing
123-
values that should be exposed as symbols to Ruby applications. When using the ``Symbol`` field type,
128+
The ``:stringified_symbol`` field type is the recommended field type for storing
129+
values that should be exposed as symbols to Ruby applications. When using the ``:symbol`` field type,
124130
Mongoid defaults to storing values as BSON symbols. For more information on the
125131
BSON symbol type, see :ref:`here <field-type-symbol>`.
126132
However, the BSON symbol type is deprecated and is difficult to work with in programming languages
127-
without native symbol types, so the ``StringifiedSymbol`` type allows the use of symbols
128-
while ensuring interoperability with other drivers. The ``StringifiedSymbol`` type stores all data
133+
without native symbol types, so the ``:stringified_symbol`` type allows the use of symbols
134+
while ensuring interoperability with other drivers. The ``:stringified_symbol`` type stores all data
129135
on the database as strings, while exposing values to the application as symbols.
130136

131137
An example usage is shown below:
@@ -170,15 +176,15 @@ migration from fields that currently store either strings or BSON symbols in the
170176

171177
.. _field-type-symbol:
172178

173-
Field Type: Symbol
179+
Field Type :symbol
174180
------------------
175181

176-
New applications should use the :ref:`StringifiedSymbol field type <field-type-stringified-symbol>`
177-
to store Ruby symbols in the database. The ``StringifiedSymbol`` field type
182+
New applications should use the :ref:`:stringified_symbol field type <field-type-stringified-symbol>`
183+
to store Ruby symbols in the database. The ``:stringified_symbol`` field type
178184
provides maximum compatibility with other applications and programming languages
179185
and has the same behavior in all circumstances.
180186

181-
Mongoid also provides the deprecated ``Symbol`` field type for serializing
187+
Mongoid also provides the deprecated ``:symbol`` field type for serializing
182188
Ruby symbols to BSON symbols. Because the BSON specification deprecated the
183189
BSON symbol type, the `bson` gem will serialize Ruby symbols into BSON strings
184190
when used on its own. However, in order to maintain backwards compatibility
@@ -201,10 +207,10 @@ snippet in your project:
201207

202208
.. _field-type-hash:
203209

204-
Field Type: Hash
210+
Field Type :hash
205211
----------------
206212

207-
When using a field of type Hash, be wary of adhering to the
213+
When using a field of type ``:hash``, be wary of adhering to the
208214
`legal key names for mongoDB <http://docs.mongodb.org/manual/reference/limits/#naming-restrictions>`_,
209215
or else the values will not store properly.
210216

@@ -213,7 +219,7 @@ or else the values will not store properly.
213219
class Person
214220
include Mongoid::Document
215221
field :first_name
216-
field :url, type: Hash
222+
field :url, type: :hash
217223

218224
# will update the fields properly and save the values
219225
def set_vals
@@ -233,21 +239,21 @@ or else the values will not store properly.
233239

234240
.. _field-type-time:
235241

236-
Field Type: Time
242+
Field Type :time
237243
----------------
238244

239-
``Time`` fields store values as ``Time`` instances in the :ref:`configured
245+
``:time`` fields store values as ``Time`` instances in the :ref:`configured
240246
time zone <time-zones>`.
241247

242248
``Date`` and ``DateTime`` instances are converted to ``Time`` instances upon
243-
assignment to a ``Time`` field:
249+
assignment to a ``:time`` field:
244250

245251
.. code-block:: ruby
246252

247253
class Voter
248254
include Mongoid::Document
249-
250-
field :registered_at, type: Time
255+
256+
field :registered_at, type: :time
251257
end
252258

253259
Voter.new(registered_at: Date.today)
@@ -259,10 +265,10 @@ local time, because the application was not configured to use UTC times.
259265

260266
.. _field-type-date:
261267

262-
Field Type: Date
268+
Field Type :date
263269
----------------
264270

265-
Mongoid allows assignment of values of several types to ``Date`` fields:
271+
Mongoid allows assignment of values of several types to ``:date`` fields:
266272

267273
- ``Date`` - the provided date is stored as is.
268274
- ``Time``, ``DateTime``, ``ActiveSupport::TimeWithZone`` - the date component
@@ -280,20 +286,20 @@ As a date & time to date conversion is lossy (it discards the time component),
280286
especially if an application operates with times in different time zones it is
281287
recommended to explicitly convert ``String``, ``Time`` and ``DateTime``
282288
objects to ``Date`` objects before assigning the values to fields of type
283-
``Date``.
289+
``:date``.
284290

285291

286292
.. _field-type-date-time:
287293

288-
Field Type: DateTime
294+
Field Type :date_time
289295
---------------------
290296

291297
MongoDB stores all times as UTC timestamps. When assigning a value to a
292-
``DateTime`` field, or when querying a ``DateTime`` field, Mongoid
298+
``:date_time`` field, or when querying a ``:date_time`` field, Mongoid
293299
converts the passed in value to a UTC ``Time`` before sending it to the
294300
MongoDB server.
295301

296-
``Time``, ``ActiveSupport::TimeWithZone`` and ``DateTime`` objects embed
302+
``Time``, ``ActiveSupport::TimeWithZone``, and ``DateTime`` objects embed
297303
time zone information, and the value persisted is the specified moment in
298304
time, in UTC. When the value is retrieved, the time zone in which it is
299305
returned is defined by the :ref:`configured time zone settings <time-zones>`.
@@ -302,7 +308,7 @@ returned is defined by the :ref:`configured time zone settings <time-zones>`.
302308

303309
class Ticket
304310
include Mongoid::Document
305-
field :opened_at, type: DateTime
311+
field :opened_at, type: :date_time
306312
end
307313

308314
Mongoid.use_activesupport_time_zone = true
@@ -332,7 +338,7 @@ doing so, the integers/floats are assumed to be Unix timestamps (in UTC):
332338
ticket.opened_at
333339
# => Fri, 14 Dec 2018 16:12:54 +0000
334340

335-
If a string is used as a ``DateTime`` field value, the behavior depends on
341+
If a ``String`` is used as a ``:date_time`` field value, the behavior depends on
336342
whether the string includes a time zone. If no time zone is specified,
337343
the :ref:`default Mongoid time zone <time-zones>` is used:
338344

@@ -354,7 +360,7 @@ If a time zone is specified, it is respected:
354360

355361
.. _field-type-regexp:
356362

357-
Field Type: Regexp
363+
Field Type :regexp
358364
------------------
359365

360366
MongoDB supports storing regular expressions in documents, and querying using
@@ -365,7 +371,7 @@ fork of `Oniguruma regular expression engine <https://github.com/kkos/oniguruma>
365371
The two regular expression implementations generally provide equivalent
366372
functionality but have several important syntax differences.
367373

368-
When a field is declared to be of type Regexp, Mongoid converts Ruby regular
374+
When a field is declared to be of type ``:regexp``, Mongoid converts Ruby regular
369375
expressions to BSON regular expressions and stores the result in MongoDB.
370376
Retrieving the field from the database produces a ``BSON::Regexp::Raw``
371377
instance:
@@ -375,7 +381,7 @@ instance:
375381
class Token
376382
include Mongoid::Document
377383

378-
field :pattern, type: Regexp
384+
field :pattern, type: :regexp
379385
end
380386

381387
token = Token.create!(pattern: /hello.world/m)
@@ -847,9 +853,20 @@ can use in our model class as follows:
847853

848854
class Profile
849855
include Mongoid::Document
850-
field :location, type: Point
856+
field :location, type: :point
857+
end
858+
859+
First, declare the new field type mapping in an initializer:
860+
861+
.. code-block:: ruby
862+
863+
# in /config/initializers/mongoid_custom_fields.rb
864+
865+
Mongoid::Fields.configure do
866+
type :point, Point
851867
end
852868

869+
853870
Then make a Ruby class to represent the type. This class must define methods
854871
used for MongoDB serialization and deserialization as follows:
855872

@@ -945,8 +962,10 @@ specifiying its handler function as a block:
945962

946963
# in /config/initializers/mongoid_custom_fields.rb
947964

948-
Mongoid::Fields.option :required do |model, field, value|
949-
model.validates_presence_of field if value
965+
Mongoid::Fields.configure do
966+
option :required do |model, field, value|
967+
model.validates_presence_of field.name if value
968+
end
950969
end
951970

952971
Then, use it your model class:

docs/release-notes/mongoid-8.0.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,40 @@ as well as ActiveRecord-compatible ``previously_new_record?`` and
276276

277277
user.destroy
278278
user.previously_persisted? # => true
279+
280+
281+
Setting Field Type as a Class is Deprecated
282+
-------------------------------------------
283+
284+
Mongoid has historically supported defining the ``field :type`` option
285+
as either a Symbol or a Class. As of Mongoid 8.0, using a Class is deprecated
286+
and Symbol is preferred. Support for ``field :type`` as a Class will be
287+
removed in a future major version of Mongoid.
288+
289+
.. code-block:: ruby
290+
291+
class Person
292+
include Mongoid::Document
293+
294+
# Deprecated; will log an warning message.
295+
field :first_name, type: String
296+
297+
# Good
298+
field :last_name, type: :string
299+
end
300+
301+
302+
Support for Defining Custom Field Type Values
303+
---------------------------------------------
304+
305+
Mongoid 8.0 adds the ability to define custom ``field :type`` Symbol values as follows:
306+
307+
.. code-block:: ruby
308+
309+
# in /config/initializers/mongoid_custom_fields.rb
310+
311+
Mongoid::Fields.configure do
312+
type :point, Point
313+
end
314+
315+
Refer to the :ref:`docs <http://docs.mongodb.org/manual/reference/fields/#custom-field-types>` for details.

lib/config/locales/en.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,33 @@ en:
172172
resolution: "When defining the field :%{name} on '%{klass}', please provide
173173
valid options for the field. These are currently: %{valid}. If you
174174
meant to define a custom field option, please do so first as follows:\n\n
175-
\_\_Mongoid::Fields.option :%{option} do |model, field, value|\n
176-
\_\_\_\_# Your logic here...\n
175+
\_\_Mongoid::Fields.configure do\n
176+
\_\_\_\_option :%{option} do |model, field, value|\n
177+
\_\_\_\_\_\_# Your logic here...\n
178+
\_\_\_\_end\n
177179
\_\_end\n
178180
\_\_class %{klass}\n
179181
\_\_\_\_include Mongoid::Document\n
180182
\_\_\_\_field :%{name}, %{option}: true\n
181183
\_\_end\n\n
182184
Refer to:
183185
https://docs.mongodb.com/mongoid/current/reference/fields/#custom-field-options"
186+
invalid_field_type:
187+
message: "Invalid field type :%{type} for field :%{field} on model '%{klass}'."
188+
summary: "Model '%{klass}' defines a field :%{field} with an unknown :type value
189+
:%{type}. This value is neither present in Mongoid's default type mapping,
190+
nor defined in a custom field type mapping."
191+
resolution: "Please provide a valid :type value for the field. If you
192+
meant to define a custom field type, please do so first as follows:\n\n
193+
\_\_Mongoid::Fields.configure do\n
194+
\_\_\_\_type :%{type}, YourTypeClass
195+
\_\_end\n
196+
\_\_class %{klass}\n
197+
\_\_\_\_include Mongoid::Document\n
198+
\_\_\_\_field :%{field}, type: :%{type}\n
199+
\_\_end\n\n
200+
Refer to:
201+
https://docs.mongodb.com/mongoid/current/reference/fields/#custom-field-types"
184202
invalid_includes:
185203
message: "Invalid includes directive: %{klass}.includes(%{args})"
186204
summary: "Eager loading in Mongoid only supports providing arguments

lib/mongoid/errors.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
require "mongoid/errors/invalid_dependent_strategy"
1616
require "mongoid/errors/invalid_field"
1717
require "mongoid/errors/invalid_field_option"
18+
require "mongoid/errors/invalid_field_type"
1819
require "mongoid/errors/invalid_find"
1920
require "mongoid/errors/invalid_includes"
2021
require "mongoid/errors/invalid_index"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module Mongoid
4+
module Errors
5+
6+
# This error is raised when trying to define a field using a :type option value
7+
# that is not present in the field type mapping.
8+
class InvalidFieldType < MongoidError
9+
10+
# Create the new error.
11+
#
12+
# @example Instantiate the error.
13+
# InvalidFieldType.new('Person', 'first_name', 'stringgy')
14+
#
15+
# @param [ String ] klass The model class.
16+
# @param [ String ] field The field on which the invalid type is used.
17+
# @param [ String ] type The value of the field :type option.
18+
def initialize(klass, field, type)
19+
super(
20+
compose_message('invalid_field_type', { klass: klass, field: field, type: type })
21+
)
22+
end
23+
end
24+
end
25+
end

0 commit comments

Comments
 (0)