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 theObservation
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'"