Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #10797 (closed defect: fixed)

Opened 11 months ago

Last modified 9 months ago

[PATCH] fix parameter parsing bug affecting hashes nested in arrays

Reported by: dipesh_batheja Assigned to: technoweenie
Priority: normal Milestone: 2.0.3
Component: ActionPack Version: edge
Severity: normal Keywords:
Cc:

Description

Here is what I am tried to do:

<% fields_for "parts[]", part do |p| -%>

<% p.fields_for "opening_balance" do |op| %>

<%= op.text_field :quantity %>

<% end %>

<% end %>

These are the params returned once i fill the data in the form:

"parts"=>[{"opening_balance"=>{}}]

This is what is expected: "parts"=>[{"opening_balance"=>{:quantity => 10}}]

I have a form that allows adding multiple parts at once, in which i get this unexpected result. On the other hand when i just have a form that allows adding single part at a time, it works fine. Is this a bug, feature? Is there any workaround?

Attachments

10797-001.patch (0.7 kB) - added by thomas.lee on 02/27/08 12:40:50.
Attaching a patch for a test to reproduce this issue: apply with "patch -p1 <1079-001.patch"
10797-002.patch (1.2 kB) - added by thomas.lee on 02/27/08 14:26:55.
Updated patch with a working fix and unit test: apply with "patch -p1 <10797-002.patch"
10797-003.patch (1.2 kB) - added by thomas.lee on 02/27/08 14:36:14.
Simplified the fix ever so slightly: apply with "patch -p1 <10797-003.patch"
10797-004.patch (1.4 kB) - added by thomas.lee on 03/02/08 14:14:18.
Added an extra unit test for complex parsing of nested form parameters (apply with patch -p1 <10797-004.patch)
10797-005.patch (1.3 kB) - added by thomas.lee on 03/11/08 08:35:59.
Fix failing unit test in patch 4: more weirdness due to #with_indifferent_access

Change History

02/27/08 12:40:50 changed by thomas.lee

  • attachment 10797-001.patch added.

Attaching a patch for a test to reproduce this issue: apply with "patch -p1 <1079-001.patch"

02/27/08 12:59:57 changed by thomas.lee

Investigating UriEncodedPairParser, I would expect to see the following for the input "a[][b][c]=d":

0. "a"                 DATA {}
1. "[]"                DATA {"a" => []}
2. "[b]"               DATA {"a" => [{}]}
3. "[c]"               DATA {"a" => [{"b" => {}}]}
4. EOS                 DATA {"a" => [{"b" => {"c" => "d"}}]}

Instead, I see something more like:

0. "a"                 DATA {}
1. "[]"                DATA {"a" => []}
2. "[b]"               DATA {"a" => [{}]}
3. "[c]"               DATA {"a" => [{"b" => {}}]}
4. EOS                 DATA {"a" => [{"b" => {}}]}

Weird stuff.

02/27/08 14:25:45 changed by thomas.lee

  • owner changed from core to thomas.lee.
  • status changed from new to assigned.

After a bit of debugging I discovered an easy-to-overlook bug in UrlEncodedPairParser#bind.

It's not immediately obvious at a glance, but when adding the first hash following the array for the earlier example of a[][b][c]:

top << {key => value}.with_indifferent_access

This actually stores a copy of value as a HashWithIndifferentAccess in the array. value is not updated to reflect the real object that is now in the array, and gets passed back to container and pushed to the top of the stack - everything added to this hash will be lost.

I'll attach a fix for the issue shortly. Can I get somebody to verify/review this?

02/27/08 14:26:55 changed by thomas.lee

  • attachment 10797-002.patch added.

Updated patch with a working fix and unit test: apply with "patch -p1 <10797-002.patch"

02/27/08 14:36:14 changed by thomas.lee

  • attachment 10797-003.patch added.

Simplified the fix ever so slightly: apply with "patch -p1 <10797-003.patch"

02/27/08 14:43:04 changed by thomas.lee

  • owner changed from thomas.lee to david.
  • status changed from assigned to new.

02/27/08 14:43:42 changed by thomas.lee

  • summary changed from nested fields_for bug to [PATCH] nested fields_for bug.

02/27/08 22:32:49 changed by thomas.lee

  • owner changed from david to core.

02/27/08 22:35:15 changed by thomas.lee

  • summary changed from [PATCH] nested fields_for bug to [PATCH] fix parameter parsing bug affecting hashes nested in arrays.

02/27/08 22:38:29 changed by mislav

+1

03/02/08 14:10:22 changed by thomas.lee

See #9030 (a duplicate of this issue) for further discussion of this issue, as well as some rationale for rejecting changes to existing semantics outside of the UriEncodedPairParser.

03/02/08 14:14:18 changed by thomas.lee

  • attachment 10797-004.patch added.

Added an extra unit test for complex parsing of nested form parameters (apply with patch -p1 <10797-004.patch)

03/11/08 07:48:22 changed by technoweenie

  • owner changed from core to technoweenie.
  • status changed from new to assigned.

I committed patch #3 in [9010]. I'm leaving this open since the last test case in patch #4 fails, highlighting another complex parsing issue.

03/11/08 08:35:59 changed by thomas.lee

  • attachment 10797-005.patch added.

Fix failing unit test in patch 4: more weirdness due to #with_indifferent_access

03/11/08 09:26:54 changed by thomas.lee

It seems the real culprit here is the #with_indifferent_access call. One can safely remove this call, remove all other fixes I've provided here and all unit tests will pass. I have a feeling that doing this will actually break other code unless there's another pass performing the Hash -> HashWithIndifferentAccess conversion higher up.

For now I'm not going to investigate further, since the immediate bug is fixed.

As an interesting aside, the following line can be removed without breaking any unit tests. Does anybody know what it's supposed to be doing? I initially thought the ordinary Hash semantics may have been at play here, but it turns out the unit tests never seem to execute the #<<:

parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)

03/13/08 03:22:28 changed by rick

  • status changed from assigned to closed.
  • resolution set to fixed.

(In [9020]) Fix more obscure nested parameter hash parsing bug. Closes #10797 [thomas.lee]