Link

Rails Nested Attributes

If you’re familiar with Ruby on Rails, you’ve no-doubt used nested attributes to create, update or delete associations. For the uninitiated, nested attributes allows you to save attributes on associated records through the parent resource. It can be extremely convenient, but can easily become an escape hatch to your RESTful API, where every object should have its own specific URI. There’s hardly anything magical happening, and Rails is really the only framework where you would expect it to work with minimal configuration. As you will see, nested attributes are merely compact Rails-specific instructions to handle CRUD operations via the parent resource.

ReactiveRecord also has built-in support for handling nested attributes, which is covered here.

Contents

  1. Creating
  2. Updating
  3. Deleting
  4. Relationship types

Nested attributes tend to look like this: Say you have an article resource which has many tag resources. To update the title of your article, your request body might look like this:

{ "title": "How to use the CDI instrument" }

PUT /articles/24 202 Accepted

But say you also wanted to create tags, and your Article model accepted nested attributes for tags. Your request body would look something like this:

Creating

{
  "tags_attributes": [
    { "label": "Aviation" },
    { "label": "Navigation" },
    { "label": "How-To" }
  ]
}

PUT /articles/24 202 Accepted

Even though we’ve made a PUT request to update a specific article resource, we’ve included instructions to create three tag resources. We would expect the response to look like this:

{
  "id": 24,
  "title": "How to use the CDI instrument",
  "tags": [
    { "id": 1, "label": "Aviation" },
    { "id": 2, "label": "Navigation" },
    { "id": 3, "label": "How-To" }
  ]
}

Notice how in the request, we included only the label attribute for each tag. In the response, not only are tags present in the tags array (not tags_attributes), but there are IDs present for each tag we created. That’s exactly what we expect to happen with no ID present in the request. It’s shorthand instructions to create a new record with the nested attributes. When we do include an ID, we’re instructing Rails to UPDATE a resource using the provided attributes. This is a little funky because we’re nesting an update action within an update action! With the following request body, we’re saying update the post tag with ID 2 with a new label:

Updating

{
  "tags_attributes": [{ "id": 2, "label": "VOR Navigation" }]
}

PUT /articles/24 202 Accepted

If our nested attributes configuration allows for destroying via nested attributes, we would destroy a resource via nested attributes by including a _destroy attribute along with the ID. Our request body would look like this:

Deleting

{
  "tags_attributes": [{ "id": 3, "_destroy": true }]
}

PUT /articles/24 202 Accepted

Relationship types

The above examples describe a parent with a has many type relationship with a child. However, nested attributes works with any kind of association, as long as it’s configured in the Rails model.

  • parent -> children
  • children -> parent
  • child -> parent
  • parent -> child

You can learn more about how to configure nested attributes via the official Rails documentation. Nested attributes have built-in support in ReactiveRecord, which is covered here.