back to notes

Rails: ActiveRecord: Accept Nested Attributes For (accepts_nested_attributes_for)

The purpose of accepts_nested_attributes_for (ANAF) is to allow child models (Observation) to be created at the same time as a parent model (Post), which sounds exactly like your use case. You do this by including a collection of child attributes along with the attributes for the parent model in a request to the parent model's create action.

There are a few steps to enable this behavior.

Add acceptsnestedattributes_for to your Post model

class Post < ActiveRecord::Base
  has_many :observations

  # add this =>
  accepts_nested_attributes_for :observations
end

Update Strong Parameters to allow the nested params

You need to let your controller know to accept the attributes that will be coming in for the nested model.

class PostsController
  # ...

  def post_params
    params.require(:post).permit(
      ... 
      observations_attributes: [:attr1, :attr2]
  end
end

observation_attributes is a hash key whose value is an array of all the attributes of the Observation which should be allowed.

Important Add inverse_of to the Post model

Here is where people get tripped up. As you pointed out above, an Observation has a foreign key to a Post, but since we are creating both types of records at the same time, we won't yet have a post_id to associate with.

The inverse_of option sets up a relationship between the parent/child association and lets the Post be created before the Observation objects and then link them together. Without this, if you try sending a request using AFAF, you'll get back an error "observations.post":["must exist"].

class Post < ActiveRecord::Base
  has_many :observations, inverse_of: :post
end

Read more about inverse_of.

Send a request

Now all you need to do is send a POST request to the /posts endpoint and include parameters for the Post and its nested Observations

// Sample params for JSON request
{
   "post": {
      "title": "Foo"
      "content": "Bar",
      "observations_attributes": [
         { "attr1": "Baz 1", "attr2": "Buzz 1" },
         { "attr1": "Baz 2", "attr2": "Buzz 2" }
      ]
   }
}

or

curl -i -H "Content-Type: application/json" \
        -H "Accept: application/json" \
        -X POST http://dev.carlosramireziii.com:3000/articles \
        -d "post[title]='Foo'&post[content]='Bar'&post[observations_attributes][0][attr1]='Baz'&post[observations_attributes][0][attr2]='Buzz'"


last updated january 2017