I’ve seen a lot of examples of this online, and it took a while for me to get it right, so I decided to document it. The two cases I’ve used this for: Vanity URLs, e.g. trying to open a user’s profile at /u/amingilani Obfuscated URLs, e.g. trying to make the difficult to guess such as URL /transactions/601585f7–0f4a-41e8-bd04-b2eb24262fb4 Both cases differ only by the fact that the slug is randomly generated in the latter. Quick definitions: : part of the URL to identify the record Slug : a unique identifier for database records Primary key : Universal unique identifier, a 128 bit generated identifier that depending on the implementation is either guaranteed or is very likely to be unique. UUID Overview: We’ll add a unique column to our database table slug We’ll generate a unique slug on creation (only for the 2nd use-case) We’ll use the slugs in URLs Adding a column to our database slug We’ll need to ensure that our slug is unique, and always present. You can name it “username” or anything more semantic if it’s meant to be part of the model. class AddSlugToRecommendations < ActiveRecord::Migration[5.1]def changeadd_column :transactions, :slug, :string, null: falseadd_index :transactions, :slug, unique: trueendend Generating a unique slug on creation We’ll use the library that ships with rails to generate a unique UUID. If the UUID (by whatever sorcery) already exists, a new one will be generated instead. securerandom This is only important, if we’re trying to obfuscate our URLS. Ignore this step if you’re letting users set something like username class Transaction < ApplicationRecordbefore_create :set_slug private def set_slugloop doself.slug = SecureRandom.uuidbreak unless Transaction.where(slug: slug).exists?endendend Use the slug in URLS This will have to be set in multiple places: use the param in routes :slug lookup records using the param :slug Override the method to return the attribute instead of Model#to_param slug id Tell your routes to use the slug param: Rails.application.routes.draw doresources :transactions, param: :slugend Now your routes will look like this: edit_transaction GET /transactions/:slug/edit(.:format)transaction GET /transactions/:slug(.:format)PATCH /transactions/:slug(.:format)PUT /transactions/:slug(.:format)DELETE /transactions/:slug(.:format) For your controller to lookup records by the slug, stop using the and use the param instead: id slug class TransactionsController < ApplicationControllerbefore_action :set_transaction, only: [:show, :edit, :destroy] private def set_transaction = Transaction.find_by slug: params[:slug]endend @transaction Let’s override the method so that works: Model#to_param form_for @transaction class Transaction < ApplicationRecord...def to_paramslugend...end Why my way is the best Unless you’re creating a distributed application with distributed database nodes that need a collision free method to generate primary keys, you don’t need randomly generated ids. You’re just looking for a quick and easy way to hack , which is why this method is awesome. URLS Using a string as a primary key is significantly slower than an integer during lookups, so every call will be slower. Model#children Using a slug for URL lookups means the slow performance will be limited to URL lookups, which is what you wanted in the first place.