diff --git a/source/data-modeling/validation.txt b/source/data-modeling/validation.txt index 5d87a0a2..6909df02 100644 --- a/source/data-modeling/validation.txt +++ b/source/data-modeling/validation.txt @@ -305,7 +305,7 @@ database. The following methods trigger your validation rules, so - ``save()`` - ``update()`` -When you use the ``-!`` suffixed version of the preceding methods, +When you use the ``!``-suffixed version of the preceding methods, {+odm+} returns an ``Mongoid::Errors::Validations`` exception if validation fails for an object. diff --git a/source/includes/interact-data/crud.rb b/source/includes/interact-data/crud.rb new file mode 100644 index 00000000..85dbc78b --- /dev/null +++ b/source/includes/interact-data/crud.rb @@ -0,0 +1,266 @@ +# start create! example +Person.create!( + first_name: "Heinrich", + last_name: "Heine" +) + +Person.create!([ + { first_name: "Heinrich", last_name: "Heine" }, + { first_name: "Willy", last_name: "Brandt" } +]) + +Person.create!(first_name: "Heinrich") do |doc| + doc.last_name = "Heine" +end +# end create! example + +# start create example +Person.create( + first_name: "Heinrich", + last_name: "Heine" +) + +class Post + include Mongoid::Document + validates_uniqueness_of :title +end + +posts = Post.create([{title: "test"}, {title: "test"}]) +posts.map { |post| post.persisted? } # => [true, false] +# end create example + +# start save! example +person = Person.new( + first_name: "Esmeralda", + last_name: "Qemal" +) +person.save! + +person.first_name = "Malik" +person.save! +# end save! example + +# start save example +person = Person.new( + first_name: "Tamara", + last_name: "Graham" +) +person.save + +person.first_name = "Aubrey" +person.save(validate: false) +# end save example + +# start attributes example +person = Person.new(first_name: "James", last_name: "Nan") +person.save + +puts person.attributes +# end attributes example + +# start reload example +band = Band.create!(name: 'Sun 1') +# => # + +band.name = 'Moon 2' +# => # + +band.reload +# => # +# end reload example + +# start reload unsaved example +existing = Band.create!(name: 'Photek') + +band = Band.new(id: existing.id) +band.reload + +puts band.name +# end reload unsaved example + +# start update attributes! example +person.update_attributes!( + first_name: "Maximilian", + last_name: "Hjalmar" +) +# end update attributes! example + +# start update attributes example +person.update_attributes( + first_name: "Hasan", + last_name: "Emine" +) +# end update attributes example + +# start update attribute example +person.update_attribute(:first_name, "Jean") +# end update attribute example + +# start upsert example +person = Person.new( + first_name: "Balu", + last_name: "Rama" +) +person.upsert + +person.first_name = "Ananda" +person.upsert(replace: true) +# end upsert example + +# start touch example +person.touch(:audited_at) +# end touch example + +# start delete example +person = Person.create!(name: 'Edna Park') + +unsaved_person = Person.new(id: person.id) +unsaved_person.delete +person.reload +# end delete example + +# start destroy example +person.destroy +# end destroy example + +# start delete all example +Person.delete_all +# end delete all example + +# start destroy all example +Person.destroy_all +# end destroy all example + +# start new record example +person = Person.new( + first_name: "Tunde", + last_name: "Adebayo" +) +puts person.new_record? + +person.save! +puts person.new_record? +# end new record example + +# start persisted example +person = Person.new( + first_name: "Kiana", + last_name: "Kahananui" +) +puts person.persisted? + +person.save! +puts person.persisted? +# end persisted example + +# start field values default +class Person + include Mongoid::Document + field :first_name +end + +person = Person.new + +person.first_name = "Artem" +person.first_name # => "Artem" +# end field values default + +# start field values hash +class Person + include Mongoid::Document + + field :first_name, as: :fn +end + +person = Person.new(first_name: "Artem") + +person["fn"] +# => "Artem" + +person[:first_name] = "Vanya" +# => "Artem" + +person +# => # +# end field values hash + +# start read write attributes +class Person + include Mongoid::Document + + def first_name + read_attribute(:fn) + end + + def first_name=(value) + write_attribute(:fn, value) + end +end + +person = Person.new + +person.first_name = "Artem" +person.first_name +# => "Artem" +# end read write attributes + +# start read write instance +class Person + include Mongoid::Document + field :first_name, as: :fn +end + +person = Person.new(first_name: "Artem") +# => # + +person.read_attribute(:first_name) +# => "Artem" + +person.read_attribute(:fn) +# => "Artem" + +person.write_attribute(:first_name, "Pushkin") + +person +# => # +# end read write instance + +# start attributes= example +person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" } +# end attributes= example + +# start write_attributes example +person.write_attributes( + first_name: "Jean-Baptiste", + middle_name: "Emmanuel", +) +# end write_attributes example + +# start atomically example +person.atomically do + person.inc(age: 1) + person.set(name: 'Jake') +end +# end atomically example + +# start default block atomic example +person.atomically do + person.atomically do + person.inc(age: 1) + person.set(name: 'Jake') + end + raise 'An exception' + # Name and age changes are persisted +end +# end default block atomic example + +# start join_contexts atomic +person.atomically do + person.atomically(join_context: true) do + person.inc(age: 1) + person.set(name: 'Jake') + end + raise 'An exception' + # Name and age changes are not persisted +end +# end join_contexts atomic \ No newline at end of file diff --git a/source/interact-data.txt b/source/interact-data.txt index 2e3e3707..f211ae5d 100644 --- a/source/interact-data.txt +++ b/source/interact-data.txt @@ -14,6 +14,7 @@ Interact with Data .. toctree:: :caption: Interact with Data + Perform Data Operations Specify a Query Modify Query Results Search Text @@ -23,6 +24,9 @@ Interact with Data In this section, you can learn how to use {+odm+} to interact with your MongoDB data. +- :ref:`mongoid-data-crud`: Learn how to create, read, update, and + delete documents in a collection. + - :ref:`mongoid-data-specify-query`: Learn how to construct queries to match specific documents in a MongoDB collection. diff --git a/source/interact-data/crud.txt b/source/interact-data/crud.txt new file mode 100644 index 00000000..41eede34 --- /dev/null +++ b/source/interact-data/crud.txt @@ -0,0 +1,690 @@ +.. _mongoid-data-crud: + +======================= +Perform Data Operations +======================= + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: ruby framework, odm, create data, edit + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to use {+odm+} to perform CRUD (create, +read, update, delete) operations to modify the data in your MongoDB +collections. + +{+odm+} supports CRUD operations that you can perform by using other +{+language+} mappers such as Active Record or Data Mapper. +When using {+odm+}, general persistence operations perform atomic +updates on only the fields that you change instead of writing the +entire document to the database each time, as is the case with other +ODMs. + +Create Operations +----------------- + +You can perform create operations to add new documents to a collection. If +the collection doesn't exist, the operation implicitly creates the +collection. The following sections describe the methods you can use to +create new documents. + +create! +~~~~~~~ + +Use the ``create!`` method on your model class to insert one or more +documents into a collection. If any server or validation errors occur, +``create!`` raises an exception. + +To call ``create!``, pass a hash of attributes that define the document +you want to insert. If you want to create and insert multiple documents, +pass an array of hashes. + +This example shows multiple ways to call ``create!``. The first example +creates one ``Person`` document, and the second example creates two ``Person`` +documents. The third example passes a ``do..end`` block to ``create!``. {+odm+} +invokes this block with the documents passed to ``create!`` as +arguments. The ``create!`` method attempts to save the document at the +end of the block: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start create! example + :end-before: end create! example + +create +~~~~~~ + +Use the ``create`` method to insert a new document or multiple new documents into a +database. ``create`` does not raise an exception on validation errors, +unlike the ``!``-suffixed version. ``create`` does raise exceptions on +server errors, such as if you insert a document with a duplicate ``_id`` field. + +If ``create`` encounters any validation errors, the document is not inserted +but is returned with other documents that were inserted. You can use the +``persisted?``, ``new_record?`` or ``errors`` methods to verify the +documents that were inserted into the database. + +This example shows how to use ``create`` to insert new documents +into MongoDB. The first example shows how to insert a ``Person`` +document. The second example attempts to insert two ``Post`` documents, +but the second document fails validation because it contains a duplicate +title. The example then uses the ``persisted?`` method to confirm which +documents were successfully inserted into the collection: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start create example + :end-before: end create example + +To learn more about the ``persisted?`` and ``new_record?`` methods, see +the :ref:`mongoid-persistence-attr` section of this guide. + +save! +~~~~~ + +Use the ``save!`` method to atomically save changed attributes to the collection or +to insert a new document. ``save!`` raises an exception if there are any +server or validation errors. You can use the ``new`` method to create a new document +instance. Then, use ``save!`` to insert the document into the database. + +The following example shows how to use ``save!`` to insert a new ``Person`` +document and update the ``first_name`` field of the existing document: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start save! example + :end-before: end save! example + +save +~~~~ + +The ``save`` method does not raise an exception if there are any +validation errors. ``save`` still raises an exception if there are any +server errors. The method returns ``true`` if all changed attributes +are saved, and ``false`` if any validation errors occur. + +You can pass the following options to ``save``: + +- ``validate: false``: To bypass validations when saving the new + document or updated attributes. + +- ``touch: false``: To not update the ``updated_at`` field when + updating the specified attributes. This option has no effect when + inserting a new document. + +The following code uses ``save`` to insert a new document. It then updates +that document and applies the ``validate: false`` option. + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start save example + :end-before: end save example + +Read Operations +--------------- + +You can perform read operations to retrieve documents from a collection. + +.. _mongoid-read-attributes: + +attributes +~~~~~~~~~~ + +You can use the ``attributes`` method to retrieve the attributes of a +model instance as a hash. This hash also contains the attributes of all +embedded documents. + +The following example shows how to use ``attributes``: + +.. io-code-block:: + + .. input:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start attributes example + :end-before: end attributes example + + .. output:: + :language: console + + { "_id" => BSON::ObjectId('...'), + "first_name" => "James", + "last_name" => "Nan" + } + +reload +~~~~~~ + +You can use the ``reload`` method to access the most recent version of a +document from MongoDB. When you reload a document, {+odm+} also reloads any embedded +associations in the same query. However, {+odm+} does not reload +referenced associations. Instead, it clears these values so that they +are loaded from the database during the next access. + +When you call ``reload`` on a document, any unsaved changes to the document +are lost. The following code shows how to call ``reload`` on a document: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start reload example + :end-before: end reload example + +The preceding example updates the ``name`` field on the ``band`` document, +but does not save the new value. Because {+odm+} did not persist the +change to the ``name`` value, ``name`` contains the original value saved +to the database. + +.. note:: Document Not Found Errors + + When {+odm+} cannot find a document in the database, by default it raises a + ``Mongoid::Errors::DocumentNotFound`` error. You can set the + ``raise_not_found_error`` configuration option to ``false`` in your ``mongoid.yml`` + file to direct {+odm+} to save a new document and set its attributes to + default values. Generally, it also changes the value of the ``_id`` + field. For this reason, we do not recommend using ``reload`` when + ``raise_not_found_error`` is set to ``false``. + +Reload Unsaved Documents +++++++++++++++++++++++++ + +When you call ``reload`` on a document that is not persisted, the method performs +a ``find`` query on the document's ``_id`` value. + +The following example calls ``reload`` on a document that has not been +saved and prints out the ``name`` field value. ``reload`` performs a +``find`` operation using the document's ``_id`` value, which causes +{+odm+} to retrieve the existing document in the collection: + +.. io-code-block:: + :copyable: true + + .. input:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start reload unsaved example + :end-before: end reload unsaved example + + .. output:: + :visible: false + + Photek + +Update Operations +----------------- + +You can perform update operations to modify existing documents in a +collection. If you attempt to update a deleted document, {+odm+} raises +a ``FrozenError`` exception. + +update_attributes! +~~~~~~~~~~~~~~~~~~ + +You can use the ``update_attributes!`` method to update the attributes of an +existing model instance. This method raises an exception if it encounters +any validation or server errors. + +The following example shows how to use ``update_attributes!`` to update +the ``first_name`` and ``last_name`` attributes of an existing document: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start update attributes! example + :end-before: end update attributes! example + +.. tip:: + + {+odm+} provides the nested attributes feature that allows you to + update a document and its nested associations in one call. To learn + more, see the :ref:`mongoid-data-nested-attr` guide. + +update_attributes +~~~~~~~~~~~~~~~~~ + +The ``update_attributes`` method does not raise an exception on +validation errors. The method returns ``true`` if it passes validation +and the document is updated, and ``false`` otherwise. + +The following example shows how to use ``update_attributes``: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start update attributes example + :end-before: end update attributes example + +update_attribute +~~~~~~~~~~~~~~~~ + +You can use the ``update_attribute`` method to bypass validations and +update a *single* attribute of a model instance. + +The following example shows how to use ``update_attribute`` to update +the value of a document's ``first_name`` attribute: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start update attribute example + :end-before: end update attribute example + +upsert +~~~~~~ + +You can use the ``upsert`` method to update, insert, or replace a +document. + +``upsert`` accepts a ``replace`` option. If you set this option to ``true`` +and the document that calls ``upsert`` already exists in the database, +the new document replaces the one in the database. Any fields in the +database that the new document does not replace are removed. + +If you set the ``replace`` option to ``false`` and the document exists in the +database, it is updated. {+odm+} does not change any fields other than the +ones specified in the update document. If the document does not exist in the +database, it is inserted with the fields and values specified in the +update document. The ``replace`` option is set to ``false`` by default. + +The following example shows how to use ``upsert`` to first insert a new +document, then replace it by setting ``replace: true``: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start upsert example + :end-before: end upsert example + +touch +~~~~~ + +You can use the ``touch`` method to update a document's ``updated_at`` +timestamp to the current time. ``touch`` cascades the update to any of +the document's ``belongs_to`` associations. You can also pass another +time-valued field as an option to also update that field. + +The following example uses ``touch`` to update the +``updated_at`` and ``audited_at`` timestamps: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start touch example + :end-before: end touch example + +Delete Operations +----------------- + +You can perform delete operations to remove documents from a collection. + +delete +~~~~~~ + +You can use the ``delete`` method to delete a document from the database. When you +use ``delete``, {+odm+} does not run any callbacks. If the document is not +saved to the database, ``delete`` attempts to delete any document with +the same ``_id`` value. + +The following example shows how to use the ``delete`` method and +demonstrates what happens when you delete a document that is not saved +to the database: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start delete example + :end-before: end delete example + +In the preceding example, {+odm+} raises a ``Mongoid::Errors::DocumentNotFound`` +error when you call ``reload`` because ``unsaved_person.delete`` deletes +the ``person`` document because the two documents have the same value +for ``_id``. + +destroy +~~~~~~~ + +The ``destroy`` method operates similarly to ``delete``, except {+odm+} +runs callbacks when you call ``destroy``. If the document is not found +in the database, ``destroy`` attempts to delete any document with +the same ``_id``. + +The following example shows how to use ``destroy``: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start destroy example + :end-before: end destroy example + +delete_all +~~~~~~~~~~ + +The ``delete_all`` method deletes all documents from the collection that +are modeled by your {+odm+} model class. ``delete_all`` does not run +callbacks. + +The following example shows how to use ``delete_all`` to delete all +``Person`` documents: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start delete all example + :end-before: end delete all example + +destroy_all +~~~~~~~~~~~ + +The ``destroy_all`` method deletes all documents from the collection +that are modeled by your {+odm+} model class. This can be an expensive +operation because {+odm+} loads all documents into memory. + +The following example shows how to use ``destroy_all`` to delete all +``Person`` documents: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start destroy all example + :end-before: end destroy all example + +.. _mongoid-persistence-attr: + +Persistence Attributes +---------------------- + +The following sections describe the attributes that {+odm+} provides that +you can use to check if a document is persisted to the database. + +new_record? +~~~~~~~~~~~ + +The ``new_record?`` attribute returns ``true`` if the model instance is +*not saved* to the database yet, and ``false`` otherwise. It checks for +the opposite condition as the ``persisted?`` attribute. + +The following example shows how to use ``new_record?``: + +.. io-code-block:: + + .. input:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start new record example + :end-before: end new record example + + .. output:: + :visible: false + + true + + false + +persisted? +~~~~~~~~~~ + +The ``persisted?`` attribute returns ``true`` if {+odm+} persists the +model instance, and ``false`` otherwise. It checks for the opposite +condition as the ``new_record?`` attribute. + +The following example shows how to use ``persisted?``: + +.. io-code-block:: + + .. input:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start persisted example + :end-before: end persisted example + + .. output:: + :visible: false + + false + + true + +Access Field Values +------------------- + +{+odm+} provides several ways to access field values on a document. The +following sections describe how you can access field values. + +Get and Set Field Values +~~~~~~~~~~~~~~~~~~~~~~~~ + +There are multiple ways to get and set field values on a document. If you explicitly +declare a field, you can get and set this field value on the document directly. +The following example shows how to set and get the ``first_name`` field for a +``Person`` instance: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start field values default + :end-before: end field values default + +The preceding example first uses the ``first_name`` attribute to set a +value, then calls it again to retrieve the value. + +You can also use the ``[]`` and ``[] =`` methods on a {+odm+} model instance to +access attributes by using hash syntax. The ``[]`` method is an alias +for the ``read_attribute`` method and the ``[] =`` method is an alias +for the ``write_attribute`` method. The following example shows how to +get and set the aliased ``first_name`` field by using the ``[]`` and +``[]=`` methods: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start field values hash + :end-before: end field values hash + +To learn more about these methods, see the following +:ref:`mongoid-read-write-attributes` section of this guide. + +.. _mongoid-read-write-attributes: + +read_attribute and write_attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``read_attribute`` and ``write_attribute`` methods to specify +custom behavior when reading or writing fields. You can use these methods +when defining a model or by calling them on model instances. + +To use ``read_attribute`` to get a field, pass the name of the field to the method. +To use ``write_attribute`` to set a field, pass the name of the field and the +value to assign. + +The following example uses ``read_attribute`` and ``write_attribute`` in +a model definition to define ``first_name`` and ``first_name=`` as methods that +are used to read and write to the ``fn`` attribute: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start read write attributes + :end-before: end read write attributes + +You can also call ``read_attribute`` and ``write_attribute`` directly on a +model instance to get and set attributes. The following example uses these methods +on a model instance to get the ``first_name`` attribute and set it to the value +``"Pushkin"``. + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start read write instance + :end-before: end read write instance + +Bulk Write Attributes +~~~~~~~~~~~~~~~~~~~~~ + +You can write to multiple fields at the same time by using the ``attributes=`` +or ``write_attributes`` methods on a model instance. + +To use the ``attributes=`` method, call the method on a model instance and +pass a hash object that contains the fields and values that you want to set. +The following example shows how to use the ``attributes=`` method to set the +``first_name`` and ``middle_name`` fields on a ``person`` document: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start attributes= example + :end-before: end attributes= example + +To use the ``write_attributes`` method, call the method on a model instance +and pass the fields and values that you want to set. The following example +shows how to use the ``write_attributes`` method to set the ``first_name`` and +``middle_name`` fields on a ``person`` document: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start write_attributes example + :end-before: end write_attributes example + +Atomic Update Operators +----------------------- + +{+odm+} provides support for the following update operators that you can +call as methods on model instances. These methods perform operations +atomically and skip validations and callbacks. + +The following table describe the operators supported by {+odm+}: + +.. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Operator + - Description + - Example + + * - ``add_to_set`` + - Adds a specified value to an array-valued field. + - ``person.add_to_set(aliases: "Bond")`` + + * - ``bit`` + - Performs a bitwise update of a field. + - ``person.bit(age: { and: 10, or: 12 })`` + + * - ``inc`` + - Increments the value of a field. + - ``person.inc(age: 1)`` + + * - ``pop`` + - Removes the first or last element of an array field. + - ``person.pop(aliases: 1)`` + + * - ``pull`` + - Removes all instances of a value or values that match a specified + condition from an array field. + - ``person.pull(aliases: "Bond")`` + + * - ``pull_all`` + - Removes all instances of the specified values from an array + field. + - ``person.pull_all(aliases: [ "Bond", "James" ])`` + + * - ``push`` + - Appends a specified value to an array field. + - ``person.push(aliases: ["007","008"])`` + + * - ``rename`` + - Renames a field in all matching documents. + - ``person.rename(bday: :dob)`` + + * - ``set`` + - | Updates an attribute on the model instance and, if the instance + is already persisted, performs an atomic ``$set`` on the field, bypassing + validations. + + | ``set`` can also deeply set values on ``Hash`` fields. + + | ``set`` can also deeply set values on ``embeds_one`` associations. + If a model instance's ``embeds_one`` association document is ``nil``, one + is created before the update. + + | ``set`` cannot be used with ``has_one`` associations. + + - .. code-block:: ruby + + person = Person.create!(name: "Ricky Bobby") + # Updates `name` in the database + person.set(name: "Tyler Durden") + + * - ``unset`` + - Deletes a particular field in all matching documents. + - ``person.unset(:name)`` + +To learn more about update operators, see :manual:`Update Operators +` in the MongoDB {+server-manual+}. + +Group Atomic Operations +~~~~~~~~~~~~~~~~~~~~~~~ + +To group atomic operations together, you can use the ``atomically`` method +on a model instance. {+odm+} sends all operations that you pass to an +``atomically`` block in a single atomic command. + +.. note:: Use Transactions to Modify Multiple Documents Atomically + + Atomic operations apply to one document at a time. Therefore, nested + ``atomically`` blocks cannot make changes to multiple documents in one + atomic operation. To make changes to multiple documents in one atomic + operation, use a multi-document transaction. To learn more about + transactions, see the :ref:`mongoid-data-txn` guide. + +The following example shows how to use ``atomically`` to atomically +update multiple fields in a document: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start atomically example + :end-before: end atomically example + +You can nest ``#atomically`` blocks when updating a single document. By +default, {+odm+} performs atomic writes defined by each block when the +block ends. The following example shows how to nest ``atomically`` blocks: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start default block atomic example + :end-before: end default block atomic example + +In the preceding example, the ``$inc`` and ``$set`` operations are executed at +the end of the inner ``atomically`` block. + +Join Contexts ++++++++++++++ + +The ``atomically`` method accepts a ``join_context: true`` option to specify that +operations execute at the end of the outermost ``atomically`` block. When you +enable this option, only the outermost block, or the first block where ``join_context`` +is ``false``, writes changes to the database. The following example sets +the ``join_context`` option to ``true``: + +.. literalinclude:: /includes/interact-data/crud.rb + :language: ruby + :start-after: start join_contexts atomic + :end-before: end join_contexts atomic + +In the preceding example, {+odm+} performs the ``$inc`` and ``$set`` operations at the +end of the outermost ``atomically`` block. However, since an exception is raised +before the block ends and these operations can run, the changes are not +persisted. + +You can also enable context joining globally, so that operations execute in the +outermost ``atomically`` block by default. To enable this option +globally, set the ``join_contexts`` configuration option to ``true`` in +your ``mongoid.yml`` file. To learn more about {+odm+} configuration +options, see :ref:`configuration-options`. + +When you globally set ``join_contexts`` to ``true``, you can use the +``join_context: false`` option on an ``atomically`` block to run +operations at the end of the block for that block only. + +Additional Information +---------------------- + +To learn more about specifying query filters, see the +:ref:`mongoid-data-specify-query` guide. + +To learn more about setting validation rules on your models, see the +:ref:`mongoid-modeling-validation` guide. + +To learn more about defining callbacks, see the +:ref:`mongoid-modeling-callbacks` guide.