Simplest alternative IDs with Rails

Rails actions default on using record IDs. But what if we want to change the URL to something prettier, something that doesn’t leak the record ID in the database?

Luckily, there is a simple answer that doesn’t require you to change much. Let’s say we want to use a slug in the URL for a Team model.

We start with the routes and the param option:

# config/routes.rb
Rails.application.routes.draw do
  resources :teams, param: :slug do
    member do
      get "another_route"

The param option will change the paths from /teams/:id to /teams/:slug and allow us to use params[:slug] in the controller. All paths generated with resources will be changed.

At the controller level, we now have to look up records with this new alternative ID:

class TeamsController < ApplicationController
  before_action :set_team



  def set_team
    # Instead of @team = Team.find!(params[:id])
    @team = Team.find_by!(slug: params[:slug])

Now things work, but we would need to change all _paths and _url references to point to the new routes. However, these path helpers depend on Model#to_param method which we can override with the new default:

class Team < ActiveRecord::Base

  def to_param

That’s it. Almost no work and we fixed our IDs-leaking URLs to something better. Don’t forget on the slug index for a quick lookup.


I wrote a complete guide on web application deployment. Ruby with Puma, Python with Gunicorn, NGINX, PostgreSQL, Redis, networking, processes, systemd, backups, and all your usual suspects.

More →