Overview
In this guide, you can learn how to define nested attributes on models to enable data operations on documents and their associations. After you define a nested attribute, you can specify updates to top-level and associated documents in a single parameter hash. This might be useful if your application requires editing multiple documents within a single form.
Behavior
You can enable nested attributes for any association, embedded or
referenced. To add a nested attribute for an association, provide the
association name to the accepts_nested_attributes_for macro when
defining a model class.
The following code defines embedded associations on the Band model
class and includes the accepts_nested_attributes_for macro:
class Band include Mongoid::Document embeds_many :albums belongs_to :producer accepts_nested_attributes_for :albums, :producer end
Note
Autosave Enabled
When you add nested attribute functionality to a referenced association, Mongoid automatically enables autosave for that association.
When you enable nested attributes behavior on an association, Mongoid adds a special method to the base model. You can use this method to update the attributes.
The method name is the association name suffixed with _attributes. For
example, the setter method to update the producers association is
producer_attributes.
You can use this method directly, or you can use the name of the method as an attribute in the updates for the top-level class. In this case, Mongoid calls the appropriate setter method internally.
The following code retrieves an instance of Band, then uses the
nested attribute update method producer_attributes to set a value
for the association document:
# Retrieves a Band instance band = Band.where(name: 'Tennis').first # Updates the "producer" association band.producer_attributes = { name: 'Alaina Moore' }
There are multiple ways to update a nested attribute:
Use the
<association name>_attributessetter method.Use the
attributessetter method and specify<association name>_attributesin the value to update the associations.Use the
update_attributessetter method and specify the attribute names in the value to update the associations.Use the
updatemethod and specify<association name>_attributesin the value to update the associations.Use the
createmethod and specify<association name>_attributesin the value to create the associations.
The following example demonstrates how to create a Band instance
with associated album records in a single statement:
band = Band.create( name: 'Tennis', albums_attributes: [ { name: 'Swimmer', year: 2020 }, { name: 'Young & Old', year: 2013 }] )
Creating Nested Documents
You can create new nested documents by using the nested attributes
feature. When creating a document, omit the _id field. The following
code uses the update method to create a nested album document
on an existing Band instance:
band = Band.where(name: 'Vampire Weekend').first band.update(albums_attributes: [ { name: 'Contra', year: 2010 } ])
This action appends the new document to the existing set without changing any existing nested documents.
Updating Nested Documents
You can update existing nested documents by using the nested attributes
feature. To instruct Mongoid to update a nested document by using
attributes, pass the document's _id value to the update
method. The following example uses the _id value of an albums
entry to update the year field:
band = Band.where(name: 'Vampire Weekend').first # Retrieves the first entry from the albums array album = band.albums.first # Updates the entry by passing the _id value band.update(albums_attributes: [ { _id: album._id, year: 2011 } ])
Important
No Matching Document
If Mongoid does not match a document that has the specified _id
value, it raises a Mongoid::Errors::DocumentNotFound exception.
Delete Nested Documents
You can delete nested documents by specifying the _destroy
attribute to the update method. To enable deletion of nested
document, you must set allow_destroy: true in the
accepts_nested_attributes_for declaration, as shown in the following
code:
class Band # ... accepts_nested_attributes_for :albums, allow_destroy: true end
The following code uses the _destroy attribute to delete the first
albums entry of a Band instance:
band = Band.where(name: 'Vampire Weekend').first # Retrieves the first entry from the albums array album = band.albums.first # Deletes the entry by passing the _id value band.update(albums_attributes: [ { _id: album._id, _destroy: true } ])
Important
No Matching Document
If Mongoid does not match a document that has the specified _id
value, it raises a Mongoid::Errors::DocumentNotFound exception.
Combine Operations on Nested Documents
You can perform multiple data operations on nested documents by using the nested attributes feature.
The following code creates a nested document, updates an existing
document, and deletes a document in the albums array of a Band
instance:
band = Band.where(name: 'Yeah Yeah Yeahs').first # Performs multiple data changes band.update(albums_attributes: [ { name: 'Show Your Bones', year: 2006 }, { _id: 1, name: 'Fever To T3ll' }, { _id: 2, _destroy: true } ])
Additional Information
To learn more about querying, see the Specify a Document Query guide.
To learn more about performing CRUD operations, see the Perform Data Operations guide.
To learn more about associations, see the Associations guide.