Reverse rails routing: find the action name from the URL - ruby-on-rails

I understand how to turn :controller, :action, :etc into a URL. I'm looking to do the reverse, how can the action that the rails router will call be found from the URL?

With Rails 3 you can do:
Rails.application.routes.recognize_path('/areas/1')
=> {:controller=>"areas", :action=>"show", :id=>"1"}

someone else might have a shorter way to do this, but if you are just evaluating a URL, then you go to the ActionController::Routing::RouteSet class
for a config.routes.rb
map.resources :sessions
the code to find is:
ActionController::Routing::Routes.recognize_path('/sessions/new', {:method => :get})
#=> {:controller => 'sessions', :action => 'new'}
Right:
ActionController::Routing::Routes.recognize_path('/sessions/1/edit', {:method => :get})
#=> {:controller => 'sessions', :action => 'edit', :id => 1}
Wrong - without the method being explicitly added, it will default match to /:controller/:action/:id:
ActionController::Routing::Routes.recognize_path('/sessions/1/edit')
#=> {:controller => 'sessions', :action => '1', :id => 'edit'}
If you are within the action and would like to know, it is quite a bit easier by calling params[:action]
everything you ever wanted to know about routeset can be found here: http://caboo.se/doc//classes/ActionController/Routing/RouteSet.html#M004878
Hope this helps!

Related

creating a link_to for custom route

I have a custom route (if I am doing that correctly, this is the first time I have done this) that looks like this:
map.connect 'purchases/type/:type', :controller => 'purchases', :action => 'index'
so I want to create a link_to that would use that url /purchases/type/(somenumber)
or I am completely open for a better way to do it.
Edit:
I am trying to use a category (type) to filter on the index. So if I click the link that would be /purchases/type/1 that would show all the items from type 1. I dont want this in the show, and I could do it with /purchases/?type=1, but im trying to make the urls look better.
Untested but I believe this is what you want...
map.purchase_type 'purchases/type/:type', :controller => 'purchases', :action => 'index'
Then
link_to 'foo', purchase_type_path(:type => 'your_type')
Good luck.
Based on http://www.tutorialspoint.com/ruby-on-rails-2.1/rails-routes.htm (section "named routes"), I'd try the following:
map.purchases_for_type 'purchases/type/:type', :controller => 'purchases', :action => 'index'
And I assume you'd then call it with link_to 'link text', purchases_for_type(#type_param)
For reference, I'll include the Rails3 way to do it:
match '/purchases/type/:type' => 'purchases#index', :as => "purchases_for_type", :via => "get"
Or better yet (RESTful):
match '/type/:type/purchases' => 'purchases#index', :as => "purchases_for_type", :via => "get"
You'd then call it with link_to 'link text', purchases_for_type(#type_param)

will_paginate route only works on page > 1

I have the following routes defined:
map.resources :categories, :has_many => :downloads
map.resources :downloads, :member => {:go => :get}, :collection => {:tag => :get}
map.connect '/downlods/page/:page', :controller => 'downloads', :action => 'index'
map.connect '/categories/:category_id/downloads/page/:page', :controller => 'downloads', :action => 'index'
For some reason, the first page that the will_paginate helper is called on causes links with ?page=2 to be rendered, while subsequent pages have links with /downloads/page/2. Do you know what might be causing this?
If you simply declare a route with map.connect, it can be hit and miss as to how it's routed if you do something like:
link_to("Next", :page => 2)
What you might want to do is name the route and then use it that way:
map.downloads_paginated '/downloads/page/:page', :controller => 'downloads', :action => 'index'
Then you use the route by name:
link_to("Next", downloads_paginated_path(2))
These are much more reliable.
As a note, you have '/downlods' in your path instead of '/downloads' but I'm not sure that'd be causing the trouble described.

Creating a Custom Rails Route

I am attempting to create a custom route in rails and am not sure if I am going about it in the right way. Firstly I have a RESTful resource for stashes that redirects to mystash as the controller:
map.resources :stashes, :as => 'mystash'
site.com/mystash goes to :controller => 'stashes', :action => 'show'
Which is what I want. Now is where it gets somewhat confusing. I would like to be able to add conditional params to this route. Ultimately I would like to have a route that looks like this:
site.com/mystash/zoomout/new/quiz_on/
I have places this in routes:
map.connect 'mystash/:zoom/:nav_option/:quiz',
:controller => 'stashes',
:action => 'show'
map.connect 'mystash/:zoom/:nav_option',
:controller => 'stashes',
:action => 'show'
map.connect 'mystash/:zoom',
:controller => 'stashes',
:action => 'show'
map.connect 'mystash',
:controller => 'stashes',
:action => 'show'
My routes have ended up looking like this in the browser:
site.com//mystash/zoomin?nav_option=New&quiz=quizon
and this is what one of my links looks like:
<%= link_to "In", stash_path("zoomin", :nav_option => #nav_option, :quiz => #quiz) %>
Any help is appreciated, I am pretty new to custom routes!
You should be giving these routes different names instead of the default, or you should be specifying your route with a hash and not a X_path call. For instance:
map.stash_zoom_nav_quiz 'mystash/:zoom/:nav_option/:quiz',
:controller => 'stashes',
:action => 'show'
map.stash_zoom_nav 'mystash/:zoom/:nav_option',
:controller => 'stashes',
:action => 'show'
Keep in mind that when you declare a named route, the parameters in the path must be specified in the X_path call with no omissions, and not as a hash.
link_to('Foo', stash_zoom_nav_quiz_path(#zoom, #nav_option, #quiz))
link_to('Bar', stash_zoom_nav_path(#zoom, #nav_option))
The alternative is to not bother with named routes and let the routing engine figure it out on its own:
link_to('Foo', :controller => 'stashes', :action => 'show', :zoom => #zoom, :nav_option => #nav_option, :quiz => #quiz)
If you're uncertain what routes are defined, or how to call them, always inspect the output of "rake routes" very carefully. You can also write functional tests for routes with the assert_routing method.

Rails, routing many named routes to one action

Is there a simpler way of writing this:
map.old_site_cusom_packages '/customs_packages_options.html', :controller => :public, :action => :redirect_to_home
map.old_corporate '/corporate.html', :controller => :public, :action => :redirect_to_home
map.old_track '/track.html', :controller => :public, :action => :redirect_to_home
map.old_links '/links.html', :controller => :public, :action => :redirect_to_home
map.old_contact '/contact.html', :controller => :public, :action => :redirect_to_home
I want to send many named routes to one action on one controller, I'm making sure url's left over from an old site redirect to the correct pages.
Cheers.
Use the with_options method:
map.with_options :controller => :public, :action => :redirect_to_home do |p|
p.old_site_custom_packages '/customs_packages_options.html'
p.old_corporate '/corporate.html'
p.old_track '/track.html'
p.old_links '/links.html'
p.old_contact '/contact.html'
end
You can always write a multi-purpose route with a regular expression to capture the details:
old_content_names_regexp = Regexp.new(%w[
customs_packages_options
corporate
track
links
contact
].join('|'))
map.old_content '/:page_name.html',
:controller => :public,
:action => :redirect_to_home,
:requirements => {
:page_name => old_content_names_regexp
}
That should capture specific pages and redirect them accordingly. A more robust solution is to have some kind of lookup table in a database that is checked before serving any content or 404-type pages.
Edit: For named routes, it's an easy alteration:
%w[
customs_packages_options
corporate
track
links
contact
].each do |old_path|
map.send(:"old_#{old_path}",
"/#{old_path}.html",
:controller => :public,
:action => :redirect_to_home,
)
end
In most cases the old routes can be rewritten using the singular legacy route listed first. It's also best to keep the routing table as trim as possible. The second method is more of a crutch to try and bridge the old routes.

Rails will_paginate routing caching duplicate pages

I use the will_paginate plug-in.
In oder to generate routes that I can cache ( /posts/index/2 instead of /posts?page=2) I added the following to my routes.rb:
map.connect '/posts/index/1', :controller => 'redirect', :url => '/posts/'
map.connect 'posts/index/:page',
:controller => 'posts',
:action => 'index',
:requirements => {:page => /\d+/ },
:page => nil
The first line redirects /posts/index/1 to /posts/ using a redirect controller, to avoid having a duplicate page.
Is there something wrong with the way I set up the 'posts/index/:page' rule?
I thought adding :requirements => {:page => /\d+/ } would ensure that /post/index/ without a :page parameter should not work, but /posts/index.html is getting cached.
How can I redirect /posts/index/ to /posts/ to avoid having both /posts.html and /posts/index.html ?
Thanks
UPDATE
I simply added
map.connect '/posts/index/', :controller => 'redirect', :url => '/posts/'
And I'm not getting duplicate pages anymore.
However, I still don't uderstand why I was getting /posts/index.html. Any explanations or suggestions on how to make this rule more succinct are welcome ;)!
map.connect '/posts/index/1', :controller => 'redirect', :url => '/posts/'
map.connect '/posts/index/', :controller => 'redirect', :url => '/posts/'
map.connect 'posts/index/:page',
:controller => 'posts',
:action => 'index',
:requirements => {:page => /\d+/ },
:page => nil
Here I found possible answer to your question.
I think that adding :page => nil can override previous condition. So maybe when you remove this part, it will work as you expected.

Resources