/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!