Nested Attributes
On this page
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>_attributes
setter method.Use the
attributes
setter method and specify<association name>_attributes
in the value to update the associations.Use the
update_attributes
setter method and specify the attribute names in the value to update the associations.Use the
update
method and specify<association name>_attributes
in the value to update the associations.Use the
create
method and specify<association name>_attributes
in 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 Query guide.
To learn more about performing CRUD operations, see the Perform Data Operations guide.
To learn more about associations, see the Associations guide.