Docs Menu
Docs Home
/ / /
Mongoid
/

Nested Attributes

On this page

  • Overview
  • Behavior
  • Creating Nested Documents
  • Updating Nested Documents
  • Delete Nested Documents
  • Combine Operations on Nested Documents
  • Additional Information

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.

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 }]
)

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.

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.

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.

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 } ])

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.

Back

Transactions and Sessions