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"
end
end
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
...
private
def set_team
# Instead of @team = Team.find!(params[:id])
@team = Team.find_by!(slug: params[:slug])
end
end
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
slug
end
end
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.
Get Test Driving Rails while it's in prerelease.