rails 3.0 routing - redirect globbed route - ruby-on-rails

In my routes file we originally had this rout set up:
match '/search/*tag' => 'search#search'
We now want to remove the word 'search' from the url. So I added a new route:
match '/*tag' => 'search#search'
That all works beautifully. We wanted to update the old route to redirect to the new one to keep seo and bookmarks working.
match '/search/*tag' => redirect {|params| "/#{params[:tag]}"}
However this is pluralizing the term.
Input url: www.fubar.com/search/work
Becomes: www.fubar.com/works
What is causing this and how do I stop it from pluralizing the tag?
Might be relevant: We need to use /*tag instead of /:tag because we sometimes have a list of tags. I.e. www.fubar.com/work/web/video

Turns out everything worked once I cleared my cache. Browsers remember 301 redirects (and I forgot that and was apparently kept serving a previous broken redirect.
match '/search/*tag' => redirect { |params| "/#{params[:tag]}" }
match '/*tag' => 'search#search'

All I can recommend is stuffing a Rails.logger.debug{ params.inspect } inside the block to redirect. That'd at least give you a start on debugging it. Rails routing can be tricky and brittle when you stray from the happy path, and knowing whether the issue is in the recognition (i.e. that the match for *tags is being pluralized) or in routing (that the result from the redirection is being pluralized) would be the first place to look.

Related

Ruby on Rails redirect how to pass params in routes file

We recently changed the product name on our website from 'bracelets' to 'wristbands' and need to keep the old routes around for SEO purposes.
Essentially, these routes
www.hostname.com/products/bracelets/series-1/
www.hostname.com/products/bracelets/series-1/small-purple
should route to
www.hostname.com/products/wristbands/series-1/
www.hostname.com/products/wristbands/series-1/small-purple
I am reading the tutorial here http://guides.rubyonrails.org/routing.html#redirection and looks like i'll be using the block syntax, but am still not sure how to do the route properly. I'm looking to learn more about the routes file as well, so any information would be great. Thanks in advance
match "/bracelets/:name" => redirect {|params| "/wristbands/#{params[:name]}" }
EDIT:
OK i've been playing with it for a bit, and here is how it is working with what I have tried
match "/products/bracelets/:name/:name2" => redirect {|params| "/products/wristbands/#{params[:name].pluralize}/#{params[:name2].pluralize}" }
Input URL:
localhost:3000/products/bracelets/series-1/small-purple
Output URL: localhost:3000/products/wristbands
Error Message: Invalid Product: series-1
(So the match worked, but the redirect didn't)
If I change the match to inspect params like this:
match "/products/balance-bracelets/:name/:name2" => redirect {|params| "/products/wristbands/#{params.inspect}" }
I get the following:
/products/wristbands/{:name=>"series-1", :name2=>"small-purple"}
So it appears it isn't recognizing the second slash '/' or something. Any Ideas?
I'm was at the same situation and that works for me:
match "/products/bracelets/:name/:name2" => redirect {|params, request| "/products/wristbands/#{params[:name].pluralize}/#{params[:name2].pluralize}" }
I've passed two agruments into the block.
You can do this in Rails 5.
match '/products/bracelets/:name/:name2', to: "/products/wristbands/%{name}/%{name2}"

Remove controller_name from URL in Rails 3 and use custom string instead of id

Since the beginning I always hat this one problem with rails, short urls without the controller name.
For example, I have a blog and I don't want any dates or controller names in the url, I already have a Page model with a unique field url in my database. Rails works great with such urls:
jeena.net/pages/1
And when I modify the model I even can get it to use
jeena.net/pages/foo
But it seems not to matter what I do I can not get it to work with just:
jeena.net/foo
Of course I want the index page still to work with
jeena.net/pages
And I want creating new pages and updating old pages to work too in some was as well as the link_to()-method. All suggestions are appreciated.
To define that route, try adding the following to your routes.rb:
match '/:id' => 'your_controller#your_action'
This will pretty much match everything to the id of your model. And that's not very nice... You don't want to route youe_host/pages to the pages controller, with an id equal to 'pages'... To prevent that from happening, make sure to put that line on the end of the routes.rb file. The router uses the first route that matches the path received, so putting that line on the end of it will make sure that it will only match your route after it ran out of other meaningful options.
A better practice would be to pass regexp constraints to the router, so that it will only match ids with a specific format, like that:
match '/:id' => 'your_controller#your_action', :constraints => { :id => /your_regexp/ }
Refer to the guides if you have doubts about the rails rounting system. It is pretty well written and covers lots of important things.
Rails rounting - Official Guides
edit: to create a named route, one that you can call in your controllers and override the normal routes that you are probably creating with resource, you have to provide the :as => parameter in your routes.rb
match '/:id' => 'your_controller#your_action', :as => some_name
Then you'll be able to call it in your controller/views like this:
link_to some_name_path(#my_string_id)
Hope this helps. And take a time to read the guides, it has really lots of useful info, including more details about creating named routes.

Dynamic root path route

How can I use dynamic root route if it depends on... weather, or current time, or whatever?
I thought about two ways: ApplicationController level and Rack redirect.
With first solution I will check my dynamic state and redirect to particular page.
Second solution is little more native as far as it uses routes level
For example
root :to => proc { |env| [ 302, {'Location'=> some_code }, [] ] }
But what I hope to see is how can I use simple lambda for route option like:
root :to => "mycontroller#myaction", :some_param => proc{ DateTime.now.hour }
It doesn't work but it shows my expectation
I'm not sure why you'd need to initialize a parameter in the routing table when the same thing could be done in the controller:
params[:some_param] = DateTime.now.hour
You can also do the redirection inside the controller as required instead of leaning so heavily on the routing table using the redirect_to method.
Has anyone figured this out? Even though this question is a decade old now I still don't see a clean way of doing this in Rails. I have a route constraint for the root path. My need is once they get to that action then a few conditions would be checked and based on that the request should be ultimately processed by another controller action. I could do redirect_to but then the URL shown in the browser also changes, which is not what I want. If they are hitting abc.com they should still be kept at abc.com and not redirected to abc.com/home or something else. Anyone figured this out?

How to redirect (301) when changed routing translation?

I am looking for an easy way to make redirects in my application.
SITUATION:
I have routes like this:
http://myapp.com/authors/5-hemingway/books/1-moby-dick
The routes are translated this way (using gem 'i18n_routing'):
http://myapp.com/acutores/5-hemingway/libros/1-moby-dick
Now, I changed translation of acutores to scriptores. Easy step but I'd like to redirect all routes that contained an old "acutores" resource name to routes with "scriptores" instead.
My guess is, I should play in routes.rb with:
match "/acutores" => redirect("/scriptores")
But how to do it efficiently for all cases where 'acutores' appear? (especially with nested routes)
This redirects /acutores/something to /scriptores/something but fails with plain /acutores:
match "/acutores/*path" => redirect("/scriptores/%{path}")
This seems to handle both:
match "/acutores(/*path)" => redirect {|params| "/scriptores/#{params[:path]}"}
http://guides.rubyonrails.org/routing.html#redirection
http://guides.rubyonrails.org/routing.html#route-globbing
--edit
This will get rid of all the trailing slashes:
match "/acutores(/*path)" => redirect{ |params| "/scriptores/#{params[:path]}".chomp("/") }
I had issues with browser caching redirects, so empty the cache after modifications.

Custom Rails route query

I'm putting together a short URL functionality for an app I'm working on and now have it working and turning longer URLs into a short URL by base36 encoding the ID of a record pointing to the longer URL, for example:
http://localhost:3000/7ps -> http://localhost:3000/the/long/url
I am struggling to write a route which will intercept requests for the short URL whilst still allowing requests for other valid URLs in the app.
Is there a route I can use which will only target base36 encoded values after the domain?
Thanks for any help!
You can add:
map.encoded ":encoded_url", :controller => :encoded_urls, :action => :please_decode_me
at the end of your routes. Then it shoudl catch everything that is not catched by other routes.
The short answer is "it depends." You can add a route at the end of your routes file as a catch-all. However, if you have any real routes that are one word long, this will eventually fail.
For example: If you have a path that looks like http://localhost:3000/home which is it? Is that the home page or the short URL for object #825062? Any single-word path you have in your app is going to have this issue.
A very easy way around this would be to add a single character as the first directory in your URI.
http://localhost:3000/r/abc123
Or whatever letter you want. Then you can easily map anything that starts with /r/ to your short-URL lookup controller.
map.connect "/r/:short_url", :controller => "controller_name", :action => "name_of_action_that_looks_up_short_urls"

Resources