10
votes

Hell frens

I want to show a username instead of user_id in user's show page.

For example,

a usr_id 300 for a user named harry exist in database. So how to show

http://localhost:3000/harry

instead of

http://localhost:3000/user/300

in the url.

Can this be done within from the routes file?

Thanks

3

3 Answers

15
votes

This is commonly referred to as a vanity URL, and with a little caution you can handle this quite easily. First...

  1. Make sure this is the last thing in your routes. You don't want your usernames overriding another controller's namespace.
  2. Use a sensible exclude list to prevent users from having usernames like admin, support, official, secure, etc.

In your routes:

# the simple case
get '/:username' => 'users#show', :constrain => { :username => /[a-zA-Z-]+/ }

# ...with vanity_url_path(@user) helpers
get '/:username' => 'users#show', :as => 'vanity_url'

# or routing something more complicated with all the default resourceful routes
resources :users, :path => '/:username'

# or even just defining a bunch of routes for users with this format
controller :users, :path => '/:username' do
  get '/profile', :action => :profile    #=> /johnsmith/profile => UsersController#profile
end

In the above code, I avoided duplicating the :constrain option for each route for clarity. You will want to adjust the regular expression to match your usernames, and then make sure you do have it on whichever route you go with.

If this is going to be the default way of accessing users from within your application (ie. not just a convenient way to access the profile of a user), you will want to override the to_param method on your Users model. This allows you to use the url_for helpers like form_for @user without specifying additional arguments.

class User
  def to_param
    username
  end
end

Another quick tip: if you're playing with your routes and trying to do anything more than the basics, be sure to call $ rake routes often from the command line to see what routes Rails currently recognizes. Cleaning up ones you don't need is good to do, too. ;)

4
votes

If you want to have /:username, then try this on your routes.rb file (THIS SHOULD BE THE LAST LINE OF THE BLOCK! - Last route created!)

match "/:id", :to => "users#show", :as => :friendly_user

Then, just to make it less horrible, you can use the make_permalink gem to create friendly url-names easily and override the to_param method in your model

# models/user.rb
make_permalink :username    

def to_param
  permalink
end

And to make it even better, override the User.find method to work by permalink or by id

def self.find(query)
  self.find_by_username(query) || super(query)
end

That will work for User.find(1) or User.find(my_username).

Hope that helps,

Nicolás Hock Isaza

0
votes

try something like this in routes.rb

map.user_permalink 'users/:user_name', :controller => 'users', :action => 'show'

later in views use it like this:

<%= link_to user.name, user_permalink_path(user.user_name.parameterize) %>

I'm not sure if code will work simply by paste it, but you get the point :)