This project is archived and is in readonly mode.
Params hash is incorrect for nested arrays
Reported by David Röthlisberger | May 6th, 2008 @ 10:05 PM
Say you have a form with fields for creating several contacts; each contact has fields for several phone numbers. The html might look like this:
<!-- first contact, 2 telephones -->
<input name="contact[][name]" ... />
<input name="contact[][telephone][][area_code]" ... />
<input name="contact[][telephone][][number]" ... />
<input name="contact[][telephone][][area_code]" ... />
<input name="contact[][telephone][][number]" ... />
The Contacts have not been created yet (they do not yet exist in the DB) so as there is no DB ID for the contacts, they will be stored in the params hash in a "contacts" array (as opposed to a "contacts" hash, which would be the case if the contacts had DB IDs). Same for the Telephones.
So this is what I'd expect in the params hash:
{ "contact" => [
{ "name" => "nnn",
"telephone" => [
{ "area_code" => "nnn", "number" => "nnn" },
{ "area_code" => "nnn", "number" => "nnn" }
]
}
]
}
After all, that is what the "telephone" array would look like if it wasn't nested inside "contact" -- i.e. with
<input name="telephone[][number]" />
Instead, I get something like this:
{ "contact" => [
{ "name" => "nnn" },
{ "telephone" => ["area_code" => "nnn"] },
{ "telephone" => ["number" => "nnn"] },
{ "telephone" => ["area_code" => "nnn"] },
{ "telephone" => ["number" => "nnn"] }
]
}
Using hashes (when the contacts & telephones have IDs), instead of arrays, works correctly.
Comments and changes to this ticket
-
David Röthlisberger May 6th, 2008 @ 10:01 PM
Patch with a unit test demonstrating this nested array behaviour.
-
Jeremy Kemper May 7th, 2008 @ 08:35 PM
- State changed from new to invalid
-
Jeremy Kemper May 7th, 2008 @ 08:37 PM
There's nothing to distinguish which hash keys belong to which element of the array. Looks like you expect the parser to 'remember' previously-seen hash keys and start on a new array element when a key is repeated (?)
-
David Röthlisberger May 7th, 2008 @ 09:07 PM
Exactly. After all, it seems like it 'remembers' previous keys when there no nested arrays:
<input name="telephone[][area_code]" ... /> <input name="telephone[][number]" ... /> <input name="telephone[][area_code]" ... /> <input name="telephone[][number]" ... />
correctly gives:
"telephone" => [ { "area_code" => "nnn", "number" => "nnn" }, { "area_code" => "nnn", "number" => "nnn" } ]
It seems to me that the parser is adding elements to the same hash (telephone[0]) until it sees an element with a key that is already present in the hash; then it creates a new hash (telephone[1]).
Why should the behaviour be different simply because "telephone" is nested inside an array? (I mean "why" not as in technical reasons, but as in a user's expectations). At least in there case where I am fully specifying all parameters for each record, in the correct order (i.e. there are no "sparse" records).
The whole parser is quite confusing and I am not the first to expect it to behave differently :-)
See e.g. http://dev.rubyonrails.org/ticke...:11
But I am happy with closing this; I have since learnt that the best way to achieve this is with the :index option to forms_for and fields_for, which over-rides the default behaviour of using the record's database id as the key in the params hashes.
-
Brad Gessler September 7th, 2008 @ 07:33 PM
- Tag set to actionpack, bug
I've had this exact same problem. Rails seems to only parse two levels deep because it doesn't remember the previously seen hash-keys.
Don't be so quick to close the issue. It looks like they're getting there with #474 for updates and creations; but I didn't see any activity on the params parser for supporting deep model saves.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>