I am using the User model with the username as paramenter instead of the id. So currently I have this in my route:
resources :u, param: :username, :as => :user, :controller => :user
But now I would like to access the user profile via /:username, but I see a problem with it. I have routes like /login, /logout, /settings. A user can change his username. Now how can I handle, so that the user cannot have usernames like this routes above?
Addressing your concern in isolation, you can ensure that conflicting usernames are prohibited using a blacklist.
class User < ApplicationRecord
validates :username, exclusion: { in: %w{ login logout settings }
end
In practice, you will also want to blacklist usernames that can be misleading or convey undue authority. For example, you wouldn't want a user with the username “admin”, “administrator”, or “site_owner” because it could confuse other users.
You can also take advantage of the way Rails prioritizes routes (top down) to ensure that named routes are always given precedence over the user route:
Rails.application.routes.draw do
get :login, to: 'sessions#new'
get '/:username', to: 'users#show'
end
GET /login #=> sessions#new
GET /foo #=> users#show
This enables you to add additional named routes over time that will take over username routes, which is a nice secondary protection.
For more on implementing vanity urls and using usernames in routes (instead of ids), I suggest taking a look at Changing user params to include their username.
Example to read in a file of blacklisted usernames for validation:
# app/models/concerns/blacklist.rb
module Blacklist
def blacklist
@_blacklist ||= File.readlines(Rails.root.join 'lib', 'blacklist.txt')
end
end
# app/models/user.rb
class User < ApplicationRecord
extend Blacklist
validates :username, exclusion: { in: blacklist }
end
You have two options here. The first is as suggested in the comments to your question: to have a list of excluded usernames and validate the user's username against that list before allowing them to create their account. Here's an example of one such list you could use.
The second is simpler: make the users route live at something like /u/username, instead of just /username.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With