diff --git a/snooty.toml b/snooty.toml index b4c9f5f9..789f516a 100644 --- a/snooty.toml +++ b/snooty.toml @@ -17,6 +17,7 @@ toc_landing_pages = [ [constants] rails-6-version = 6.0 rails-7-version = 7.1 +rails-8-version-docs = "v8.0" odm = "Mongoid" version = "9.0" full-version = "{+version+}.2" diff --git a/source/data-modeling.txt b/source/data-modeling.txt index ba6be34e..50af17cf 100644 --- a/source/data-modeling.txt +++ b/source/data-modeling.txt @@ -13,13 +13,13 @@ Model Your Data .. toctree:: :caption: Data Modeling - -In this section, you can learn how to model data in {+odm+}. - + Documents Field Behaviors Inheritance - Nested Attributes + Document Validation + +In this section, you can learn how to model data in {+odm+}. - :ref:`mongoid-modeling-documents`: Learn about the ``Document`` module. @@ -30,5 +30,5 @@ In this section, you can learn how to model data in {+odm+}. - :ref:`mongoid-modeling-inheritance`: Learn how to implement inheritance in your model classes. -- :ref:`mongoid-modeling-nested-attr`: Learn how to modify documents and - their associations in a single operation. +- :ref:`mongoid-modeling-validation`: Learn how to create document + validation rules for your model classes. diff --git a/source/data-modeling/validation.txt b/source/data-modeling/validation.txt new file mode 100644 index 00000000..9f96c72f --- /dev/null +++ b/source/data-modeling/validation.txt @@ -0,0 +1,343 @@ +.. _mongoid-modeling-validation: + +=================== +Document Validation +=================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: ruby framework, odm, schema, code example + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to define **validation rules** in your +{+odm+} models. After you implement validation into your models, {+odm+} +prevents you from running write operations that violate the validation +rules. Use document validation to restrict data types and value ranges +of document fields in your collections. + +{+odm+} includes ``ActiveModel::Validations`` from Active Record to +provide validation functionality, including an associated and uniqueness +validator. To learn more, see the `Active Record Validations +`__ +Rails guide and `ActiveModel::Validations +`__ +Rails API documentation. + +.. note:: Comparing {+odm+} and MongoDB Validation + + Validation in {+odm+} applies only in the context of your + application and differs from creating schema validation rules in + MongoDB. This means that your validation rules do not apply to write + operations that are performed outside of your application. To learn + more about MongoDB schema validation, see :manual:`Schema Validation + ` in the {+server-manual+}. + +Validation Helpers +------------------ + +{+odm+} supports Active Record validation helpers that you can use when defining your +model classes. You can use these helpers to set common validation rules +in your application, such as checking for the presence of a field, +comparing a field value to a specified value, or ensuring that a field +has a unique value. + +Define a Validation Rule +~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the ``validates`` macro to create a validation rule, then include +the validation helper and the required specifications for the rule. + +.. tip:: + + Each validation helper accepts one or more field names, which allows you + to define the same rule for multiple fields. + +The following code demonstrates how to use the ``presence`` validation +helper to require that ``Person`` instances contain a value for the +``name`` field: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-simple-val + :end-before: end-simple-val + :language: ruby + :emphasize-lines: 5 + :dedent: + +You can learn about other useful validation helpers in the +:ref:`mongoid-common-validations` section of this guide. + +.. _mongoid-common-validations: + +Common Validations +------------------ + +In this section, you can learn about the following common validation +rules and view examples that use validation helpers: + +- :ref:`mongoid-compare-validation` +- :ref:`mongoid-format-validation` +- :ref:`mongoid-inclusion-exclusion-validation` +- :ref:`mongoid-presence-absence-validation` +- :ref:`mongoid-uniqueness-validation` +- :ref:`mongoid-association-validation` +- :ref:`mongoid-other-validation` + +.. _mongoid-compare-validation: + +Comparison Rule +~~~~~~~~~~~~~~~ + +You can use the ``comparison`` helper to validate a document based on +the value of a specified field. + +The ``comparison`` helper supports the following options: + +- ``greater_than``: The value must be greater than the supplied value. +- ``greater_than_or_equal_to``: The value must be greater than or equal to the supplied value. +- ``equal_to``: The value must be equal to the supplied value. +- ``less_than``: The value must be less than the supplied value. +- ``less_than_or_equal_to``: The value must be less than or equal to the supplied value. +- ``other_than``: The value must be different than the supplied value. + +This example defines the following comparison validation rules on the +``Order`` model: + +- ``delivery_date``: Must be after (greater than) the value of ``order_date`` +- ``quantity``: Must be less than ``5`` + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-comparison + :end-before: end-comparison + :language: ruby + :emphasize-lines: 8-9 + :dedent: + +.. _mongoid-format-validation: + +Formatting Rule +~~~~~~~~~~~~~~~ + +You can use the ``format`` helper to validate a document based on +whether a field value matches a regular expression. Use the ``with`` +option to specify the regular expression. + +This example defines a format validation rule on the +``User`` model to ensure that the ``username`` field contains only +letters: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-fmt + :end-before: end-fmt + :language: ruby + :emphasize-lines: 6 + :dedent: + +.. tip:: Alternative Helper Method + + The ``Mongoid::Document`` module provides macro methods for certain + validations. Instead of using the ``format`` validation helper in the + ``validates`` macro statement, you can use the + ``validates_format_of`` method, as shown in the following code: + + .. code-block:: ruby + + validates_format_of :username, with: /\A[a-zA-Z]+\z/ + +.. _mongoid-inclusion-exclusion-validation: + +Inclusion or Exclusion Rule +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``inclusion`` and ``exclusion`` helpers to validate a +document based on whether a field value is in a specified list +of values. Use the ``in`` option to specify the list of values. + +This example defines an inclusion validation rule on the +``Order`` model to ensure that the ``shipping`` field value is one of +the accepted values: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-inclusion + :end-before: end-inclusion + :language: ruby + :emphasize-lines: 6 + :dedent: + +.. _mongoid-presence-absence-validation: + +Presence or Absence Rule +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``presence`` and ``absence`` helpers to validate a +document based on whether a field value is present or absent (empty). + +This example defines an absence validation rule on the +``Order`` model to ensure that the ``delivery_date`` field value is +either ``nil`` or an empty string: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-absence + :end-before: end-absence + :language: ruby + :emphasize-lines: 6 + :dedent: + +.. tip:: Alternative Helper Method + + The ``Mongoid::Document`` module provides macro methods for certain + validations. Instead of using the ``presence`` validation helper in the + ``validates`` macro statement, you can use the + ``validates_presence_of`` method, as shown in the following code: + + .. code-block:: ruby + + validates_presence_of :delivery_date + +.. _mongoid-uniqueness-validation: + +Uniqueness Rule +~~~~~~~~~~~~~~~ + +You can use the ``uniqueness`` helper to validate a +document based on whether a field value is unique from other values in +the collection. You can use the ``scope`` option to specify one or more +field names that {+odm+} uses to limit the uniqueness check. + +This example defines a uniqueness validation rule on the +``Person`` model to ensure that the ``first_name`` field value is +unique within documents that have the same ``last_name`` value: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-unique + :end-before: end-unique + :language: ruby + :emphasize-lines: 7 + :dedent: + +.. tip:: Alternative Helper Method + + The ``Mongoid::Document`` module provides macro methods for certain + validations. Instead of using the ``uniqueness`` validation helper in the + ``validates`` macro statement, you can use the + ``validates_uniqueness_of`` method, as shown in the following code: + + .. code-block:: ruby + + validates_uniqueness_of :first_name + + {+odm+} uses a ``primary`` read preference when you use the + ``validates_uniqueness_of`` method on a model, because if it + queries a secondary member of the replica set, it might read stale data. + + This method takes a ``conditions`` option that allows you to specify + conditions to add when {+odm+} checks for uniqueness: + + .. code-block:: ruby + + validates_uniqueness_of :name, conditions: -> { where(:age.gte => 10) } + +.. _mongoid-association-validation: + +Validate Associations +~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``validates_associated`` helper to validate any +associations that your model has. When you include this validation rule, +{+odm+} validates any association documents any time you try to +save an instance. + +.. TODO link to associations page + +This example defines an association validation rule on the +``Author`` model to run the validation rules for the embedded ``Book`` +instances: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-assoc + :end-before: end-assoc + :language: ruby + :emphasize-lines: 6 + :dedent: + +.. important:: + + Don't use the ``validates_associated`` helper on both ends of your + associations because this causes {+odm+} to perform validations in an + infinite loop. + +.. _mongoid-other-validation: + +Custom Validation Rules +~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``validates_each`` and ``validates_with`` helpers to +create custom validators. To learn more about these helpers and view +examples, see the `validates_each +`__ +and `validates_with +`__ +references in the Active Record documentation. + +To learn more about custom validators, see `Performing Custom +Validations +`__ +in the Active Record documentation. + +Behavior +-------- + +{+odm+} performs validation when you persist, or save, a document to the +database. The following methods trigger your validation rules, so +{+odm+} saves the object to the database only if it passes validation: + +- ``create()`` +- ``save()`` +- ``update()`` + +When you use the ``-!`` suffixed version of the preceding methods, +{+odm+} returns an ``Mongoid::Errors::Validations`` exception if +validation fails for an object. + +Trigger Validation +~~~~~~~~~~~~~~~~~~ + +You can run validations manually by using the ``valid?()`` method. This +method returns ``true`` if the object passes validation, and +``false`` otherwise: + +.. literalinclude:: /includes/data-modeling/validation.rb + :start-after: start-valid + :end-before: end-valid + :language: ruby + :emphasize-lines: 7, 11, 14 + :dedent: + +{+odm+} behaves differently from Active Record when running ``valid?()`` +on persisted data. Active Record's ``valid?()`` runs all +validations, but {+odm+}'s ``valid?()`` runs validations only on +documents that are in memory to optimize performance. + +Additional Information +---------------------- + +To learn more about validation methods and macros in {+odm+}, see the +:mongoid-api:`Mongoid::Validatable ` module +reference in the API documentation. + +To view a full list of validations helpers in Active Record, see the +`ActiveModel::Validations::HelperMethods +`__ +reference in the Rails API documentation. + +.. TODO link to field types guide. diff --git a/source/includes/data-modeling/validation.rb b/source/includes/data-modeling/validation.rb new file mode 100644 index 00000000..47b51e27 --- /dev/null +++ b/source/includes/data-modeling/validation.rb @@ -0,0 +1,89 @@ +# start-simple-val +class Person + include Mongoid::Document + + field :name, type: String + validates :name, presence: true +end +# end-simple-val + +# start-comparison +class Order + include Mongoid::Document + + field :order_date, type: DateTime + field :delivery_date, type: DateTime + field :quantity, type: Integer + + validates :delivery_date, comparison: { greater_than: :order_date } + validates :quantity, comparison: { less_than: 5 } +end +# end-comparison + +# start-fmt +class User + include Mongoid::Document + + field :username, type: String + + validates :username, format: { with: /\A[a-zA-Z]+\z/ } +end +# end-fmt + +# start-inclusion +class Order + include Mongoid::Document + + field :shipping, type: String + + validates :shipping, inclusion: { in: %w(standard priority overnight) } +end +# end-inclusion + +# start-absence +class Order + include Mongoid::Document + + field :delivery_date, type: String + + validates :delivery_date, absence: true +end +# end-absence + +# start-unique +class Person + include Mongoid::Document + + field :first_name, type: String + field :last_name, type: String + + validates :first_name, uniqueness: { scope: :last_name } +end +# end-unique + +# start-assoc +class Author + include Mongoid::Document + + embeds_many :books + + validates_associated :books +end +# end-assoc + +# start-valid +class Person + include Mongoid::Document + + field :name, type: String + field :age, type: Integer + + validates :age, comparison: { greater_than_or_equal_to: 0 } +end + +# Returns true +Person.new(name: "Berta Odom", age: 4).valid? + +# Returns false +Person.new(name: "Cody Peng", age: -5).valid? +# end-valid \ No newline at end of file diff --git a/source/interact-data.txt b/source/interact-data.txt index b11a2b05..2e3e3707 100644 --- a/source/interact-data.txt +++ b/source/interact-data.txt @@ -18,6 +18,7 @@ Interact with Data Modify Query Results Search Text Transactions and Sessions + Nested Attributes In this section, you can learn how to use {+odm+} to interact with your MongoDB data. @@ -32,4 +33,7 @@ MongoDB data. searches on text fields. - :ref:`mongoid-data-txn`: Learn how to perform multi-document - transactions to make atomic data changes. \ No newline at end of file + transactions to make atomic data changes. + +- :ref:`mongoid-data-nested-attr`: Learn how to modify documents and + their associations in a single operation. \ No newline at end of file diff --git a/source/data-modeling/nested-attributes.txt b/source/interact-data/nested-attributes.txt similarity index 99% rename from source/data-modeling/nested-attributes.txt rename to source/interact-data/nested-attributes.txt index 7e8296d2..fcd10dd9 100644 --- a/source/data-modeling/nested-attributes.txt +++ b/source/interact-data/nested-attributes.txt @@ -1,4 +1,4 @@ -.. _mongoid-modeling-nested-attr: +.. _mongoid-data-nested-attr: ================= Nested Attributes