Why ‘accepts_nested_attributes_for’ ?
When dealing with seemingly arbitrary “magic” in rails, source code is a great place to get answers. I could almost do nested forms blindfolded in Sinatra, but something happened in the transition to rails. There was a bit of magic that was unaccounted for.
In HTML, building a simple nested form can look like this:
<h3>First Ship’s Info:</h3>
Name: <input type=”text” name=”pirate[ships][][name]” id=”ship_name_1">
Type: <input type=”text” name=”pirate[ships][][type]” id=”ship_type_1">
Booty: <input type=”text” name=”pirate[ships][][booty]” id=”ship_booty_1">
<h3>Second Ship’s Info:</h3>
Name: <input type=”text” name=”pirate[ships][][name]” id=”ship_name_2">
Type: <input type=”text” name=”pirate[ships][][type]” id=”ship_type_2">
Booty: <input type=”text” name=”pirate[ships][][booty]” id=“ship_booty_2”>
This assumes that pirates can have many ships. The params will look like this:
{“pirate”=>{
“name”=>”Jack”,
“weight”=>”170",
“height”=>”6",
“ships”=>[
{
“name”=>”Bertha”,
“type”=>”Speed Boat”,
“booty”=>”$30000"
}, {
“name”=>”Gone Fishin’”,
“type”=>”Pirate Ship”,
“booty”=>”$3052900"
}]}}In the controller ( ideally in the model if you have one), you’ll explicitly be calling different classes to build relationships. This is what rails puts under the hood with ‘accepts_nested_attributes_for’. But in order to do that, changes the syntax, which can cause confusion for someone new to rails. Let’s look at another model:

Here we can see that we are building a new instance of a person, and that person can have many addresses. The ‘fields_for’ helper method takes an iterative role to create several new addresses. But how do these new addresses, which ‘belongs_to’ a person, get created? Our Controller and Models are almost nonexistent:


The answer, as is usually the case in rails: helper methods. In this case it’s the combination of ‘fields_for’ in the form, and ’accepts_nested_attributes_for’ in our model.
When we added these helper methods, it changed our params in a rather unexpected way, adding rails-y syntax:
{“person”=> {
“name”=>”Roberto”,
“addresses_attributes”=> {
“0”=>{
“street_address_1”=>”Not my address”,
“street_address_2”=>”Really”,
“city”=>”Rome”,
“state”=>”-”,
“zipcode”=>”00100",
“address_type”=>”work”
},
“1”=> {
“street_address_1”=>”Over there”,
“street_address_2”=>”Just a bit further”,
“city”=>”NYC”,
“state”=>”NY”,
“zipcode”=>”00000",
“address_type”=>”home”
}}},“commit”=>”Create Person”, “controller”=>”people”, “action”=>”create”}
We now have a key called “addresses_attributes”! Why did ‘forms_for’ do that? Because, we need a uniquely identified param key for the ‘accepts_nested_attributes_for’ method to link to the address model. We can see the magic happening on line 40 of the source code:

It’s writing the method ‘addresses_attributes=‘ that will access the Address model class. It only makes sense that addresses be created in the models, and this naming structure allows rails to do just that for us.
Now if only it didn’t seem so arbitrary…
