Custom Rails route query - ruby-on-rails

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"

Related

rails 3.0 routing - redirect globbed route

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.

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.

Username based URLs

http://twitter.com/codinghorror
http://twitter.com/login
These both look like twitter accounts but the second one is not. It's a system page.
How does twitter know that logout is not a username and how does it make sure that no user registers under a system page name that exist or that may come into existance in future?
In most url routing frameworks there is a precedence order for your routing rules. Usually fist come first serve, so that the first url patten that matches controls the url.
In this case lets say twitter had to routes defined
map.connect 'login', :controller => 'auth', :action => 'login'
map.connect ':username', :controller => 'user', :action => 'show'
The first route would match the url twitter.com/login , but when you type in twitter.com/coddinghorror it would fail to match the first route and then match the second.
They cannot know in advance. What development they will be doing years ahead. But of curse the could reserve words for trends, current and coming projects - just in case.
The login/logout part is easily achieved by rewriting/routing the url
/login/ - go to login code
/([a-z]+?)/ - go to user page appending $1
Good question?
My guess is that twitter has special logic that checks the username (check for special words) and utilizes URL rewriting and routing accordingly.
I'd be curious to see a snippet of the code though :)

Rails 2 Trailing Route Parameter

I'm building an article/blog website where any article may show up within a series of URL paths.
/section/article
/section/page/article
/section/page/page2/article
This works, but what if I wanted to have the page number for that article (/page/123) be bound to those URLs
/section/article/page/123/
/section/page/article/page/123
/section/page/page2/article/page/123
This would mean that I would have to create a specific route for each different url?
/:section/:page/:sub_page/:article/page/:page
This would mean that I would create dozens of URL routing paramters.
Is there anyway in rails to say that all urls may have a /page/NUMBER suffix at the end of the URL and still route normally (that is assign the NUMBER to a parameter and continue to goto the page normally)?
Route globbing, described at http://guides.rubyonrails.org/routing.html#route-globbing, might work in this situation. For example, your route might read map.connect '/:section/*page_subpage_path/page/:number', :controller => 'articles', :action => 'show'
This exact code might not work as intended, but this method might be a good direction to try. Good luck :)
If you want to create routes that are as customized as that you normally need to create a large number of routes to accommodate them. The general format is /resource/:id when using map.resource, anything other than that is left to you to specify.
Given that the Rails routes.rb file is executable ruby you can often define your routes programmatically by repeating patterns or doing combinations on arrays if required.

How to map non-REST URLS to REST ones?

I have a small rails app that has default scaffold generated routes eg. /stadia/1.xml. However I have to support legacy client app that can't construct such URLs correctly. What I need to do is to map URL in the form:
/stadia?id=1?format=xml to /stadia/1.xml
Or even something like:
/myApp?model=<model_name>?id=<id>?format=xml to /<model_name/<id>.xml
Is it possible to craft appropriate route in Rails?
I don't have good answer for this. What I would do is change first part of url to /stadia_legacy for legacy urls or change first part of urls for RESTful routes.
Then you can map in routes:
map.stadia_legacy :stadia_legacy, :controller => 'stadias', :action => 'please_redirect_me'
Then in stadias controller in action please_redirect_me you can check all params (they are availble in params hash: params[:id], params[:format] etc.) and redirect to correct url. Or you can write all routes manualy to correct controller and action.
What if you do some url rewrite in apache ?
I had a similar question. No answers so far, so it seems routes.rb config doesn't offer an easy way of doing this (routing based on query parameters), which I find surprising actually.
So an ugly workaround would be to have a 'myApp' default route, and then have a special redirecting controller which would look at the query params (because in controllers you do have access to that) and redirect accordingly.

Resources