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

Ticket #7047 (closed defect: fixed)

Opened 2 years ago

Last modified 1 year ago

[PATCH] Fix Array.to_param in url_for (including 1-2-stable branch)

Reported by: jeremymcanally Assigned to: bitsweat
Priority: high Milestone: 1.x
Component: ActionPack Version: edge
Severity: major Keywords: routes to_param to_query
Cc: ulysses, dkubb, diegal

Description

In response to #6765, this patch fixes the behavior of arrays for url_for. As detailed in the ticket, arrays normally would be converted to slashed strings (i.e., "1/2/3") rather than their proper conversion through to_param(i.e., "array[]=1&array[]=2&array[]=3"). The logic is there in the build_query_string method, but all the arrays were strings by the time they got there, so it never got used.

The problem with a simple little patch was that a route can have an array option named path that allows someone to give an array as the route's named path. For example:

map.connect :controller => 'content', :action => 'show_file', :path => %w(pages boo)

This patch simply checks to see if the option's key is path and its class Array; if so, it converts it using the slash method. Otherwise, if it's an Array, it simply adds it to the hash and lets the build_query_string properly convert it. Other types still behave as they did before.

Test case is included.

Attachments

fix_url_for_behavior_with_arrays.diff (1.2 kB) - added by jeremymcanally on 01/15/07 05:35:17.
url_for_arrays_and_hashes_with_to_query.diff (5.3 kB) - added by bgipsy on 03/05/07 10:48:48.
url_for_arrays_and_hashes_with_to_query_sorted.diff (6.7 kB) - added by dkubb on 03/05/07 21:22:25.
url_for_arrays_and_hashes_with_to_query_sorted.2.diff (6.5 kB) - added by dkubb on 03/05/07 21:49:42.
backport_6343-Allow_array_and_hash_query_parameters.diff (9.3 kB) - added by diegal on 10/11/07 05:08:35.
Backport of [6038], [6039], [6148] and [6343] to branches/1-2-stable@7831.

Change History

01/15/07 05:35:17 changed by jeremymcanally

  • attachment fix_url_for_behavior_with_arrays.diff added.

01/16/07 08:28:49 changed by peter_marklund

Thanks Jerry! I successfully applied your patch and it fixed the issue for me.

I'm confused as to what the :path => Array construct does. I can't see that in the documentation. Hopefully Jamis or someone else can blog about it and explain it to me... :-)

(in reply to: ↑ description ) 01/23/07 09:56:18 changed by ssinghi

  • priority changed from normal to high.
  • milestone changed from 1.2 to 1.x.

Here is a hack which I had to put in my environment.rb file to overcome this bug, while still continuing to use Rails 1.1.2.

class Array
  def to_param
    self
  end
end

02/16/07 20:41:02 changed by FireRabbit

This patch isn't really adequate, because if we actually wanted to construct a url that passed a ruby array named 'path', it wouldn't work. If someone actually wanted to pass a string "a/b/c", the correct thing to do would be %w(a b c).join('/').

peter - I also cannot find anything in the rails documentation about :path having special meaning in routes. Jeremy, could you please elaborate on this?

The documentation for ActiveSupport::CoreExtensions::Array::Conversions.to_string says:

"When an array is given to url_for, it is converted to a slash separated string."

I think the bug here is that this is just the wrong thing to do, and ssinghi's solution is correct.

For the record, someone has a patch that adds proper support for nested arrays/hashes to url_for here. It also changes the array to_params method to return the object, rather than a joined string.

03/04/07 03:22:36 changed by bitsweat

  • keywords set to routes to_param to_query.
  • owner changed from core to bitsweat.

FireRabbit, you can use '/*foo' in routes to pull out a param spanning multiple '/', like a file path.

The url generator should distinguish path and query parameters and substitute :foo => %w(a b c) as a/b/c if present in the route or foo[]=a&foo[]=b&foo[]=c if not.

Also see the work in #7462, which I've pointed back here.

Could you guys get together and combine the best of these patches, and use the #to_query introduced in [6038]?

03/04/07 12:44:36 changed by bitsweat

  • cc set to ulysses.
  • milestone changed from 1.x to 1.2.

03/05/07 10:48:48 changed by bgipsy

  • attachment url_for_arrays_and_hashes_with_to_query.diff added.

03/05/07 11:01:26 changed by bgipsy

Thanks for looking at #7462

Use of #to_query makes the patch lighter, as it obsoletes recursive #add_query_values I introduced there. But please note, that I had to patch to_query by adding extra to_s call there. Thats because TrueClass has its to_param method returning self, and cgi-escaping on it with gsub fails.

I left my previous test cases unchanged, so hashes & recursion seems like working fine.

03/05/07 21:22:25 changed by dkubb

  • attachment url_for_arrays_and_hashes_with_to_query_sorted.diff added.

03/05/07 21:33:54 changed by dkubb

  • cc changed from ulysses to ulysses, dkubb.

I just added a patch that adds a couple of small tweaks to bgipsy's work.

The unit test actionpack/test/controller/routing_test.rb was failing because the new build_query_string method uses to_query which quotes the query string keys, while the previous build_query_string did not. This test was expecting an unquoted key and failed. This patch fixes that.

The other change is that the query string parameters in build_query_string and Hash#to_query now sort the keys in the query string. The reason for that is that the keys in a Hash are not in any gauranteed order. This means there is a (slight) chance the query strings in your public URLs may not be consistent given the same key/value pairs. For browser and proxy caches you would want consistency in the URLs. An added bonus is that ordering the keys makes testing the generated query strings simpler.

03/05/07 21:49:42 changed by dkubb

  • attachment url_for_arrays_and_hashes_with_to_query_sorted.2.diff added.

03/06/07 07:48:55 changed by bitsweat

  • status changed from new to closed.
  • resolution set to fixed.
  • milestone changed from 1.2.3 to 1.x.

Committed in [6343]. Thanks for pitching in, all.

10/11/07 05:08:35 changed by diegal

  • attachment backport_6343-Allow_array_and_hash_query_parameters.diff added.

Backport of [6038], [6039], [6148] and [6343] to branches/1-2-stable@7831.

10/11/07 05:12:17 changed by diegal

  • cc changed from ulysses, dkubb to ulysses, dkubb, diegal.
  • status changed from closed to reopened.
  • resolution deleted.
  • summary changed from [PATCH] Fix Array.to_param in url_for to [PATCH] Fix Array.to_param in url_for (including 1-2-stable branch).

I've attached a backport of the fixes in trunk for 1-2-stable branch. It passes all tests and works ok on my 1.2.4 freezed rails.

10/11/07 05:25:46 changed by francois.beausoleil

+1, tested against r7833.

10/11/07 05:57:01 changed by bitsweat

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

(In [7834]) Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. Closes #7047.