user2345093
user2345093

Reputation: 653

Rails - Bad Practice to leave database id in url?

Is it a bad practice to leave the user's database id in the url like this:

localhost:3000/users/16/edit

If it is bad, how can I hide the id in the url? What do I have to watch out when calling the path in my view, routes.rb, etc?

If this is relevant to the discussion, the user resource looks like this in my routes.rb:

resources :users, only: [:new, :edit, :create, :update]

Upvotes: 3

Views: 437

Answers (3)

Nick
Nick

Reputation: 290

Based on your route, it looks like your users will not have a publicly visible profile. If this is the case then you can simply use example.com/settings for Users#edit and example.com/sign_up for Users#new.

  get 'settings', to: 'users#edit'
  get 'sign_up',  to: 'users#new'
  resource :users, path: '', only: [:create, :update]

If your users will indeed have a publicly visible profile in the future, then you can either use the friendly_id gem as suggested by hawk or perhaps a randomized 7 digit ID by overwriting it before creating the record. After a bit of research, this is how I ended up doing it:

  before_create :randomize_id

  private
    def randomize_id
      self.id = loop do
        random_id = SecureRandom.random_number(10_000_000)
        break random_id unless random_id < 1_000_000 or User.where(id: random_id).exists?
      end
    end  

Upvotes: 0

Thomas Klemm
Thomas Klemm

Reputation: 10856

While you can use friendly ids as described by hawk and RailsCast #314: Pretty URLs with FriendlyId, using the primary key in your routes is standard practice, maybe even best practice. Your primary key ensures the right record is being fetched whenever '/posts/1/edit' is being called. If you use a slug, you have to ensure uniqueness of this very slug yourself!

In your specific case it seems that you are building some kind of "Edit Profile" functionality. If each user is to edit only his or her own profile, you can route a Singular Resource.

Possible routes:
/profile # show profile
/profile/edit # edit profile

Then your user's primary key would not be visible from the URL. In all other models, I'd prefer to go with the id in the URL.

Upvotes: 1

hawk
hawk

Reputation: 5408

Simply override to_param in ActiveRecord::Base subclass

class User < ActiveRecord::Base
  validates_uniqueness_of :name
  def to_param #overriden
    name
  end
end

Then query it like this

user = User.find_by_name('Phusion')
user_path(user)  # => "/users/Phusion"

Alternatively you can use gem friendly_id

Upvotes: 3

Related Questions