This project is archived and is in readonly mode.
url_for <model> generates a <model>_url route instead of <model>_path
Reported by Nader Akhnoukh | October 28th, 2010 @ 12:19 AM
Rails 3.0.0
for example link_to @user will generate the equivalent of user_url. shouldn't the default behavior be user_path?
This is because url_for line 134 is calling polymorphic_url instead of polymorphic_path
Comments and changes to this ticket
-
Denis Odorcic October 28th, 2010 @ 04:17 AM
This was fixed with commit 6c95e0f8 in master. I guess it just wasn't pushed to 3-0-stable?
-
Andrew White October 28th, 2010 @ 08:09 AM
- State changed from new to needs-more-info
- Assigned user changed from Ryan Bigg to Andrew White
- Importance changed from to Low
Nader, can you confirm in what context you are using url_for? In a view the :only_path option is passed to url_for so the fact that url_for is calling polymorphic_url shouldn't make a difference. In fact polymorphic_path calls polymorphic_url itself.
Denis, I can't see anything in that commit that would change this behaviour - how are you comparing things?
-
Nader Akhnoukh October 28th, 2010 @ 04:30 PM
I'm using link_to @user from a view.
The code path goes like this:
-routing/url_for.rb:url_for (options is just the user record) # i think this is the bug, shouldn't the call to polymorphic_url be polymorphic_path (so that the default is _path) -routing/polymorphic_routes.rb:polymorphic_url which calls.. -routing/polymorphic_routes.rb:build_named_route_call which calls.. -routing/polymorphic_routes.rb:routing_type which spits out user_url because there is no routing_type in options (routing_type gets set in polymorphic_path) -
Andrew White October 28th, 2010 @ 04:55 PM
It should be first going through url_helper.rb:
http://github.com/rails/rails/blob/master/actionpack/lib/action_vie...
Can you provide a backtrace?
-
Nader Akhnoukh October 28th, 2010 @ 05:39 PM
OK, I think I see what's happening. Here's the backtrace from where the routing type is set to url:
--> #0 ActionDispatch::Routing::PolymorphicRoutes.routing_type(options#Hash) at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:147 #1 ActionDispatch::Routing::PolymorphicRoutes.build_named_route_call(records#User,...) at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:173 #2 ActionDispatch::Routing::PolymorphicRoutes.polymorphic_url(record_or_hash_or_array#User,...) at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:108 #3 ActionDispatch::Routing::UrlFor.url_for(options#User) at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/action_dispatch/routing/url_for.rb:135 #4 ApplicationController.url_for(options#User) at line /Users/nader/repo/napa/app/controllers/application_controller.rb:122 #5 Kernel.send(args#Array, blk#NilClass) at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/abstract_controller/helpers.rb:55 #6 #<Module:0x1071fcb08>.url_for at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/abstract_controller/helpers.rb:55 #7 ActionView::Helpers::UrlHelper.link_to at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/action_view/helpers/url_helper.rb:236 #8 ActionView::Helpers::UrlHelper.link_to at line /Library/Ruby/Gems/1.8/gems/actionpack-3.0.0/lib/action_view/helpers/url_helper.rb:229 #9 ActionView::CompiledTemplates._app_views_menus__login_items_html_haml___947485747_2208807400_3573310(local_assigns#Hash,...) at line /Users/nader/repo/napa/app/views/menus/_login_items.html.haml:5
As you can see in Step 4 I have a url_for defined in my application_controller. It's not doing anything besides calling super though (it was, but i commented it out to test):
def url_for(options = nil) super end
It looks like my call to super is going to the url_for in routing/url_for.rb instead of the url_for in helpers/url_helper right?
-
Nader Akhnoukh October 28th, 2010 @ 08:36 PM
Also, the reason this is a big issue for me is because my clients use CNAMEs to get to their site. I have a piece of rack middleware that looks up the CNAME and sets the request headers to the proper subdomain so the app knows what to do. With the above issue my urls get written out using the subdomain instead of the CNAME and the users are asked to reauthenticate as the session cookie isn't shared across different domains
-
Andrew White October 29th, 2010 @ 06:26 AM
- State changed from needs-more-info to invalid
Actually it shouldn't be hitting the url_for in ApplicationController - it doesn't in a test app. In fact the only way I can get it to go to the url_for in ApplicationController is to use helper_method :url_for in ApplicationController, e.g:
class ApplicationController < ActionController::Base helper_method :url_for def url_for(options = nil) super end end
Doing this reproduces your error. Is this what you're doing? If so all I can say is don't do this. If you want to override the :host option you want to be looking at default_url_options and/or url_options. A simple before_filter in ApplicationController that sets :host in default_url_options should be all that you need.
-
Nader Akhnoukh October 29th, 2010 @ 07:27 AM
Wow, that was some impressive sleuthing. That's exactly what I was doing. Thanks for the huge help.
-
Nader Akhnoukh October 29th, 2010 @ 09:30 AM
Andrew, the only thing I can't figure out is if I'm setting this in a before_filter I don't have access to the options hash. I am passing in a subdomain field with the options and based on that want to set the host. Thus overriding url_for. What's the better way to do that?
-
Andrew White October 29th, 2010 @ 09:46 AM
This should work:
class ApplicationController < ActionController::Base before_filter :set_default_host protected def set_default_host default_url_options[:host] = subdomain_to_host(request.subdomain) end end
The subdomain_to_host method is however you map the subdomain to the CNAME.
-
Nader Akhnoukh October 29th, 2010 @ 03:47 PM
Hi Andrew, sorry I wasn't clear.
I want to set the host based on some application logic. So this was my old method:
def url_for(options = nil) if options.kind_of?(Hash) && options.has_key?(:subdomain) options[:host] = with_subdomain(options.delete(:subdomain)) end super end
and in my view:
root_url(:subdomain => "xyz")
How would you recommend doing that? I suppose I could get rid of the convenience "subdomain" key and just set the host directly?
-
Andrew White October 29th, 2010 @ 03:55 PM
Firstly, why do you need to use root_url and not root_path - that way you don't have to worry about the host name. If you do need the full url then if you set the host in the controller before filter you don't need to pass in the subdomain key.
-
Nader Akhnoukh October 29th, 2010 @ 04:26 PM
Let say that for example I'm at my root app domain mydomain.com. And each of my users has their own subdomain. So in the view they each have links like root_url(:subdomain => user.subdomain) which should link to user1.mydomain.com and I also use root_url(:subdomain => false) to take people back to the main domain
So in this case don't I need root_url vs root_path as the host matters?
In this case how would I set the host in the before_filter? How would the before_filter have access to which subdomain to set as the host? Pass it as a request param or something?
-
Andrew White October 29th, 2010 @ 05:26 PM
So why not set the :host directly?
root_url :host => user.host
-
Nader Akhnoukh October 29th, 2010 @ 05:33 PM
yep, i think that might be the best solution. seems like messing with url_for just leads to trouble. thanks for all your help. just out of curiosity, do you know why there are two different url_fors?
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>