Params hash is incorrect for nested arrays

Hi all,

I have a problem with a form for multiple models, but I am not sure if
I have the right expectations for what “correct behaviour” should be.
I am fairly new to rails so I would welcome any advice.

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:

<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 etc.

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.

One way to get around this, that I can think of, is to create blank
contacts & telephones in the DB before displaying the form. But then
I’d have to make sure I deleted them if the user doesn’t submit the
form.

What it boils down to, is creating has_many :through associated
records is a pain. :slight_smile:

Thanks in advance,
Dave.

P.S. Forgot to mention I opened a ticket with an attached unit test:
http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/127

Dave R. wrote:

<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]” … />

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” }
]
}
]
}

Instead, I get something like this:

{ “contact” => [
{ “name” => “nnn” },
{ “telephone” => [“area_code” => “nnn”] },
{ “telephone” => [“number” => “nnn”] },
{ “telephone” => [“area_code” => “nnn”] },
{ “telephone” => [“number” => “nnn”] }
]
}

Um…

That is ‘technically’ the correct way for this to function.

Each one of the ‘[]’ will add a new section onto the array, there is no
way for the computer to ‘know’ which part of the array to push it into.
So, it makes a new one every time it encounters a sign like ‘[]’

The easy way to fix this is to put a number in the [] like [1], which is
the more appropriate way of doing this because it allows you to identify
things easier.

Doing

<input name=“contact[1][name]” … />
<input name=“contact[1][telephone][1][area_code]” … />
<input name=“contact[1][telephone][1][number]” … />
<input name=“contact[1][telephone][2][area_code]” … />
<input name=“contact[1][telephone][2][number]” … />

ensures that rails will interpret the request properly because the
second you do 2 contact’s in 2 form its to ambiguous to know which names
are associated with what and which telephones go where.

It doesn’t make a new array for every [] when the arrays aren’t
nested: :slight_smile:

<input name=“telephone[][area_code]” … />
<input name=“telephone[][number]” … />
<input name=“telephone[][area_code]” … />
<input name=“telephone[][number]” … />

which generates

“telephone” => [
{ “area_code” => “nnn”, “number” => “nnn” },
{ “area_code” => “nnn”, “number” => “nnn” }
]

I guess it knows to make a new array when it sees an attribute that is
already in the array.

But you’re right, once you start nesting the arrays it gets rather
complicated. And your solution is fair enough, nice and simple. I
might even use a position attribute for the key, or that might be over-
complicating things.

Thanks!
Dave.

On May 6, 5:47 pm, John H. [email protected]

I am having trouble with nested fields_for (this is on edge rails).

I want to accomplish the following:

<input name=“contact[1][name]” … />
<input name=“contact[1][telephone][1][number]” … />
<input name=“contact[1][telephone][2][number]” … />

My view code looks like:

form_for(‘contact’, contact, :index => 1) do |c|
c.text_field(:name)
c.fields_for(‘telephone’, telephone, :index => 1) do |r|
r.text_field(:number)
end
end

(I am using :index because these records don’t exist in the db yet, so
don’t have an id attribute to index with; I am incrementing
this :index myself for each subsequent record).

This generates:
<input name=“contact[1][name]” … />
<input name=“contact[telephone][1][number]” … />

i.e. “contact[1][name]” is correct,
but the nested “contact[telephone][1][number]” is missing the id for
“contact”.

I’ve tried many variations to the fields_for parameters;
for example, form_for(‘contact[]’ … )
and c.fields_for(‘telephone[]’ … )
generate
– still missing the contact id, and now the [telephone[]] braces are
all wack.

Am I doing something wrong? Is this a bug, or simply not possible?

At the moment I am contemplating rolling my own nesting by specifying
the full path to each fields_for:
fields_for “contacts[#{contact_position}][telephones]”,
telephone, :index => telephone_position

Any help greatly appreciated
Dave R…