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

Ticket #6752 (closed defect: fixed)

Opened 3 years ago

Last modified 2 years ago

wrong url construction with edge rails if params have the same names as symbols in routes

Reported by: adymo Assigned to: Ulysses
Priority: high Milestone: 1.2 regressions
Component: ActionPack Version: edge
Severity: major Keywords: url_for routes
Cc: jamis@37signals.com

Description

I've noticed the new behavior that was not seen in stable Rails. Using edge Rails I observe the following problem.

Example situation:

  • user is executing GET request to /sprint/show/205
  • there's a route: map.connect 'sprint/show/:sprint', :controller => 'task', :action => 'index'
  • in task/index.rhtml template we have:

<%= link_to "Break Me", :action => 'foo', :params => { :sprint => 1 } %>

or

<%= link_to "Break Me", :action => 'foo', :sprint => 1 %>

Problem:

  • on generated page the link is: <a href="/task/foo">Break Me</a> without the sprint parameter

Why?

  • url_for is used to build the URL
  • url_for calls the URL rewriter (UrlRewriter::rewrite_path) to get the URL path string
  • rewriter asks the request about path parameters and in our case it gets

{:controller => 'task', :action => 'index', :sprint => 205 }

  • rewriter asks the route to generate the url by passing path parameters as "recall" argument to Route::generate(options, recall, method)
  • generate method "recalls" those from the path, including "sprint" which is wrong in this case!

The conclusion is that in edge Rails parameters to the url_for can not have the same name as symbols in the route.

Attachments

use_query_params.diff (1.7 kB) - added by ulysses on 12/09/06 01:39:12.

Change History

12/04/06 18:16:39 changed by bitsweat

  • owner changed from David to Ulysses.

12/09/06 01:39:12 changed by ulysses

  • attachment use_query_params.diff added.

12/09/06 01:42:01 changed by ulysses

  • cc set to jamis@37signals.com.

Thanks for the good description!

The specific error is in extra_keys. Instead of passing the (possibly merged) hash, we should just pass the options hash. Thus we can avoid passing the recalled parameters altogether. Jamis: Can you see anything wrong with this approach?

The above diff makes said change. (Although it needs a unit test before applying.)

12/09/06 01:42:26 changed by ulysses

  • component changed from ActiveRecord to ActionPack.

12/09/06 03:58:47 changed by minam

Actually, nicholas, I think he's describing something different. He's describing a case where the resulting URL is wrong, independent of the query string.

That said, I can't seem to duplicate the error in a test case:

  def test_overriding_recalled_parameter_during_generation
    @rs.draw do |m|
      m.connect 'sprint/show/:sprint', :controller => "task", :action => "index"
      m.connect 'task/foo/:sprint', :controller => "task", :action => "foo"
    end
    given = { :action => "foo", :sprint => "1" }
    recall = { :controller => "task", :action => "index", :sprint => "205" }
    assert_equal "/task/foo/1", rs.generate(given, recall)
  end

After adding that test to the LegacyRouteSetTests suite in test/controller/routing_test.rb, all tests still pass. Is that test indicative of the problem the OP saw? Is there any way the OP could post their routes.rb file?

12/09/06 04:03:55 changed by minam

Also, I should note: the following construction is not supported:

  :params => { :sprint => 1 }

That _will_ give the result you describe. However, specifying :sprint => 1 directly ought to work, and if it is not, that is a bug. I cannot duplicate it, however.

12/09/06 04:42:32 changed by ulysses

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

(In [5709]) Fix a bug in Routing where a parameter taken from the path of the current request could not be used as a query parameter for the next. Closes #6752.

03/04/07 13:48:14 changed by bitsweat

  • keywords deleted.
  • milestone changed from 1.2 to 1.2 regressions.

03/12/07 17:06:01 changed by skwp

  • severity changed from normal to major.

This patch did not make it into Rails 1.2.2..was it supposed to? Lack of this patch causes upgrading to Rails 1.2 to be excessively painful as one must make sure to go through all the routes in the application to see if they still work. Any chance of tagging this as 1.2.2 so that at least people who have externalized rails can get the update...?

03/12/07 17:58:30 changed by bitsweat

The "1.2 regressions" milestone indicates that.

03/12/07 18:00:02 changed by bitsweat

  • status changed from closed to reopened.
  • resolution deleted.

(I can't tell whether the fix made it to the 1-2-stable branch, though.)

03/12/07 18:00:37 changed by bitsweat

  • keywords set to url_for routes.
  • priority changed from normal to high.

03/12/07 18:03:50 changed by technoweenie

Applied to stable in [6390]. Please try against the 1-2-stable branch and report success/failure.

03/12/07 18:04:58 changed by bitsweat

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

03/12/07 18:20:38 changed by skwp

I guess what was not clear to me is that I should be running 1-2-stable? My understanding is that if I wanted the latest rails I should be freezing TAG 1-2-2 because that was the last official announced release. I also assumed any critical errors such as the routing should be backpatched into that TAG?

Rails official blog announcements imply that those who want stable production releases should be running against the released tags. not the 'stable branch'...

03/12/07 18:35:23 changed by bitsweat

1.2.2 is the latest release, skwp, and it's tagged as such. A tag is a snapshot in time; a branch is an ongoing line of development.

Backports don't go to tags, they go to branches, which are released by creating new tags.

This is a bugfix going into the next release, which will be tagged 1.2.3 from the 1-2-stable branch.

I don't understand what's confusing or misleading here. Perhaps it was technoweenie's suggestion that you preview the fix prior to 1.2.3 release by working with the 1-2-stable branch directly?

03/12/07 18:40:53 changed by skwp

Ok I understand. Some people use tags as branches since svn really has no difference between a tag and a branch. For example when I release I typically push high priority fixes into the tags that have been released. Low priority fixes go into the next release branch.

I just assumed that something that seems to break most of routing should be released as soon as possible especially if it has been tested. Whether by patching the tags or pushing a 1.2.2.1 release or something like that...

I have tested 1-2-stable branch and it appears to work correctly with this patch. Thanks.

03/12/07 19:03:13 changed by bitsweat

Committing to a tag is a really bad idea, but that's another topic.

This issue is important but the sensationalism is unnecessary. Constructively participate in development: raise issues on the mailing list, write tests, contribute patches.

Thanks for your report.