views:

114

answers:

4

Right now my user profile URLs are like so:

http://example.com/users/joeschmoe

And that points to the show method in the user controller.

What I'd ideally like to do is offer user profile URLs like this:

http://example.com/joeschmoe

So, what sort of route and controller magic needs to happen to pull that off?

A: 

In routes.rb this should do the trick:

map.connect ":login", :controller => 'users', :action => 'show'

Where login is the name of the variable passed to the show method. Be sure to put it after all other controller mappings.

kibitzer
+2  A: 

This does not make sense unless you have no controllers. What happens when you want to name a controller the same as an existing user? What if a user creates a username the same as one of your controllers? This looks like a terrible idea. If you think the /user/ is too long try making a new custom route for /u/

So your custom route would be...

map.connect 'u/:id', :controller => 'my/usercontroller', :action => 'someaction'
jcm
I would seriously suggest following this advice.
jonnii
Well the thought process is the same as with any social network (ala Facebook, MySpace, etc) where a lot revolves around the profile so you want the user to be able to have the shortest URL possible to their profile.
Shpigford
Just remember that you are then going to have to put all of your controllers in app.mysite.com or something so they don't conflict with users. Or use subdomains for users as Steve Graham suggested.
jcm
The original poster wanted URLs as short as possible. I think that following jcm's advice is the best thing to do. The URLs are only *two* characters longer - hardly something to be worried about. You could probably save several GB a month by using techniques like a CDN or eliminating cookies. The concern about controllers colliding is a huge one. Just because there are "major sites that already do this" doesn't mean it's a good idea. They also have staffs of tens or hundreds of people building their sites.
Eilon
A: 

Well, one thing you need is to ensure that you don't have name collisions with your users and controllers.

Once you do that you, can add a route like this:

map.connect ':username', :controller => 'users', :action => 'show'

Another thing people have done is to use subdomains and rewrite rules in the web server, so you can have http://joeshmoe.example.com

MattMcKnight
A: 

I disagree with what jcm says about this. It's not a terrible idea at all and is used in production by the two biggest social networks Facebook and MySpace.

The route to match http://example.com/username would look like this:

map.connect ':username', :controller => 'users', :action => 'show'

If you want to go the subdomain route and map profiles to a URL like http://username.example.com/, I recommend using the SubdomainFu plugin and the resulting route would look like:

map.root :controller => 'users', :action => 'show' , :conditions => {:subdomain => /.+/}

These broad, catch all routes should be defined last in routes.rb, so that they are of lowest priority, and more specific routes will match first.

I also recommend using a validation in your User model to eliminate the possibility of a user choosing a username that will collide with current and future routes:

class User < ActiveRecord::Base
  validates_exclusion_of :username, :in => %w( messages posts blog forum admin profile )
  …
end
Steve Graham
Perfect. Thanks Steve.
Shpigford
I wouldn't trust validating against existing controller names. This could get ugly fast. I would highly recommend using the subdomain example above. But even then, it's stopping you from using sub domains in the future, or forcing you to break url compatability when you decide you want subdomains later.
jcm
I disagree. When the list of reserved names becomes large enough as to become unwieldy, I would use an Application configuration class such as http://gist.github.com/222878 in concert with a YAML config file. Then I could replace the array in the validation with AppConfig.reserved_words or similar. Also the validation is just another layer of protection. These routes should be set to the lowest priority, so in the unlikely event of a naming collision, the user would have to change their username in order to view their profile.
Steve Graham