Rails friendly url routing with open id - ruby-on-rails

I would like to use create a rails route for a user's open id. The url would look something like
http://mysite.com/identity/:html_encoded_openid
or
http://mysite.com/identity/:html_encoded_openid.xml
This would be so that the site could be queried for an open id and either view info for that identity or receive an xml document containing that information. Standard Rails stuff.
I am looking for your expertise on a few things:
Standard rails routes seem to choke the .s in an openid so that:
http://mysite.com/identity/openid
would find a route but
http://mysite.com/identity/openid.myopenid.com
would not.
What security issues would I need to look out for?
Is there a better way to encode the query, perhaps with the querystring?
And I'd rather not do the standard friendly url method of using:
my-friendly-openid-com
or
23-my-friendly-openid-com
if possible.

You could handle that second route with something like this (replace the action name with something real).
map.connect 'identity/:id', :controller => "identity",
:action => "foo",
:requirements => {:id => /(\w+\.?)+/}

Related

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

How to create custom routes for certain actions in a CakePHP controller?

Coming from Django, I'm used to be able to organize my URL routings any way I see fit. For example, user registration would exist under the /users/ url.
/users/
/users/registration/
/users/registration/optin/
/users/registration/thankyou/
However, I'm creating a user registration system in CakePHP and the default convention behaviour for url routings is /controller/action/. This yields:
/users/
/users/registration/
/users/optin/
/users/thankyou/
How can I achieve a /controller/action/custom/ style-url routing on some of my actions (where /custom/ is a sub-section, not a parameter)? Should I even be expecting to do this or am I just fighting the convention?
/controller/action/custom/ works fine by default.
It invokes ControllerController::action('custom').
If you're looking for something like invoking UsersController::thankyou() through the URL /users/registration/thankyou, you can make an appropriate route:
Router::connect('/users/registration/thankyou',
array('controller' => 'users', 'action' => 'thankyou'));
You can group routes in one rule like this:
// Routes /users/registration/optin and /users/registration/thankyou to
// UsersController::optin() and UsersController::thankyou() respectively
Router::connect('/users/registration/:action',
array('controller' => 'users'),
array('action' => '(optin|thankyou)'));
Routes are very powerful and completely flexible in Cake. As always, study the manual:
http://book.cakephp.org/view/945/Routes-Configuration
The basics are that the Router matches the route, e.g. '/users/registration/:action', against the current URL, including conditions specified in the third parameter, e.g. 'action' => '(optin|thankyou)' (the :action part has to match the RegEx /^(optin|thankyou)$/).
If it matches, it merges the defaults from the second parameter with any information extracted from the URL, so you get array('controller' => 'users', 'action' => 'thankyou') for example.
It then pushes it through CakeRoute::parse, which constructs the array you can see when doing debug($this->params) in a controller. This array is used to figure out which Controller to load and which action to invoke.
The basic RegEx and parameter matching is already very powerful, but you can go completely crazy by subclassing CakeRoute and providing a custom parse function, as briefly explained at the end of the manual. :)

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"

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.

Sending a variable through a link_to without url query in Ruby on Rails

I'm trying to send a variable through a link_to, without using url query in Ruby on Rails, from one controller's index view to be used on another controller's index.
Basically, I need to pass the Turma.id (school class id), to the Elementos_turma(peoples in the class) controller, so I can use it and filter the index: ElementosTurma.find(:all, :conditions => { :turma_id => xxxxx } ), to show the peoples of the selected class.
It it possible?
Maybe without using a session variable?
Maybe sending the variable to a method on the 1st controller, to send it the other controller? (if so how? not very RoR wise... :) )
No need for a special method to get the info you need, the magic of routes will do.
In your routes.db file, you should be able to define something like this,
map.resources :class, :has_many => :students
Then if you run 'rake routes' you should see a routes similar to this
class_students GET /classes/:class_id/students(.:format) {:controller=>"students", :action=>"index"}
You can call that path in your view like so
class_students_path(class_id)
Then in your controller you will have access to params[:class_id]
The name of the route isn't very pretty, but this should work.
EDIT--------------------------------------
According to your comment, you can't use map.resources for some reason or another...
map.class_students '/:class_id/students', :controller => 'students', :action => 'index'
That will produce the same route available in your view, same param in your controller.
That being said, I don't know how a server bug could prohibit you from using map.resources
You can not transfer data through a link without including that data in the link.
However, it sounds like you just need to be using nested resources. (Since I speak English, I'm going to not tackle another language and do what comes to me.) The URLs you want to be sending people to probably should look more like this if you want to be RESTful:
/classes/1/people/
That is the "Rails way" of indicating that you want to get people in class #1, and Rails offers built-in routing methods to make this easy. See the Rails Routing from the Outside In article in the Rails Guide.

Resources