Angelos Orfanakos

/username URLs in Rails

I recently wanted to have /:username URLs in a Rails app. This post describes how I did it.

In your User model:

class User < ApplicationRecord

Add a format validation for the allowed characters in a username:

USERNAME_REGEX = /\w+/.freeze
validates(
  :username,
  presence: true,
  format: { with: USERNAME_REGEX, allow_blank: true })

Add an exclusion validation to automatically reserve usernames that match existing routes (e.g. to prevent a posts username when a /posts route exists):

RESERVED_USERNAMES = Rails.application.routes.routes.map { |route|  route.path.spec.to_s[%r{(?<=\A/)\w+}]}.compact.uniq.freeze
validates(
  :username,
  presence: true,
  format: { with: USERNAME_REGEX, allow_blank: true },
  exclusion: { in: RESERVED_USERNAMES })

Define to_param so that the username (instead of id) is used for route path and URL helpers:

def to_param
  username
end

Finally, place the necessary route at the end of your routes file at config/routes.rb so that it matches last:

get(
  ':username',  to: 'users#show',
  as: 'user',
  constraints: { username: User::USERNAME_REGEX }
)

You can link to a user with:

<%= link_to @user.username, user_path(@user) %>

That’s it!