Rails, routing many named routes to one action - ruby-on-rails

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.

Related

Rails Routes Collision Handling

I have an interesting routing situation that I'm having some trouble handling... This is for a rails 2.3 app, here's the scenario:
route a:
/:trans_type/:country_code/:property_types
route b:
/:trans_type/:country_code/:location
These two routes share the same location in the route so there needs to be a :requirement set on either :location or :property_types to differentiate the two.
Since :location is pretty wide open, :property_types is the way to go because I have a module that can easily compile a list of of all existing property types to do a regex match against.
The problem:
/for-sale/us/apartment-loft
Since :property_types is an array, I have to parse multiple property_types out of the params object (outside of the router, obviously). If I have a case like this, it's not possible for me to do a regex match in the router against a known property type because :property_types can potentially return several hyphenated types.
My question then is, Is it possible for me to take the :property_types string and modify it specifically for the :requirements matching? If I can replace 'apartment-loft' to just be 'apartment' for that match (/^\w+/), then I have something I can realistically regex match against.
Here's what the two routes actually look like:
map.location ":transaction/:country_code/:property_types",
:controller => "search",
:action => "location",
:requirements => { :transaction => /(for-sale|for-rent|auction|new_development)/, :country_code => /\w\w/, :property_types => /(#{prop_types})/ }
map.location ":transaction/:country_code/:location",
:controller => "search",
:action => "location",
:requirements => { :transaction => /(for-sale|for-rent|auction|new_development)/, :country_code => /\w\w/}
The above implementation works fine for routes that have one property_type, but for routes that have multiple hyphenated property_types, I'm hitting a wall.
If it's feasible, I would suggest creating explicit routes and controller actions for these two cases:
map.location ":transaction/:country_code/property-types/:property_types",
:controller => "search",
:action => "by_property_type",
:requirements => { :transaction => /(for-sale|for-rent|auction|new_development)/, :country_code => /\w\w/, :property_types => /(#{prop_types})/ }
map.location ":transaction/:country_code/:location",
:controller => "search",
:action => "by_location",
:requirements => { :transaction => /(for-sale|for-rent|auction|new_development)/, :country_code => /\w\w/}
Then you don't have to worry so much about regex matching at the router and you can do it in the controller instead.

Reverse rails routing: find the action name from the URL

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!

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 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