Friendly IDs for Ruby on Rails

drnic

Dr Nic Williams

Posted on October 20, 2022

Friendly IDs for Ruby on Rails

Do you have URLs like /books/1 or /secret_things/10 and wish that they were friendlier? Also, wish the IDs were sequential and guessable?

I like Stripe's URLs, such as https://dashboard.stripe.com/test/products/prod_MG5m4q7sKvGto8. If I see the ID value prod_MG5m4q7sKvGto8 anywhere I know it belongs to a Stripe Product. cus_MG5sTiccdSlpjw? A Stripe Customer ID. Very friendly.

And the IDs are not sequential. Friendly and random. I want this.

I'm going to show you the project I use for friendly IDs, and how I add them to my Rails scaffolding generators so they are automatically enabled for every model.

rails generate scaffold Book title description:text
Enter fullscreen mode Exit fullscreen mode

And my URLs automatically pop out looking like /books/book_qYlVPJvDprRabHa0wy1xz3n9.

A quick tweak of the generated class and they might become even nicer, /books/bk_qYlVPJvDprRabHa0wy1xz3n9.

Yeah, you want this too.

prefixed_ids gem

The magic is provided by Chris Oliver's prefixed_ids rubygem.

The only requirement is that your models' id column is bigint or some other integer. I was not successful using the gem with uuid columns. But you won't need UUID IDs because you'll have publicly friendly, random IDs, and internally sequential IDs.

bundle add prefixed_ids
Enter fullscreen mode Exit fullscreen mode

Trying it out

Before we go and edit your scaffold generators, let's try it out on an existing model.

Add has_prefix_id :thing to one of your models, and go and view it in your app.

class Book
  has_prefix_id :bk
Enter fullscreen mode Exit fullscreen mode

Your boring IDs now look gloriously friendly, /books/bk_x912t423.

The gem hijacks the find and to_param methods. Everything just works.

Adding it to your model generator

You definitely want friendly IDs for all your future models. That is, when you run either:

rails g model Book title
rails g scaffold Book title
Enter fullscreen mode Exit fullscreen mode

You want the resulting app/models/book.rb to include the has_prefix_id :bk link from above.

First, copy the current Rails model.rb.tt template into your app.

If you're using Jumpstart Pro, you can skip this step.

mkdir -p lib/templates/active_record/model
curl https://raw.githubusercontent.com/rails/rails/main/activerecord/lib/rails/generators/active_record/model/templates/model.rb.tt \
  -o lib/templates/active_record/model/model.rb.tt
Enter fullscreen mode Exit fullscreen mode

This file will be used to generate all your future model class files.

In the newly created model.rb.tt file, add the 3rd line:

<% module_namespacing do -%>
class <%= class_name %> < <%= parent_class_name.classify %>
  has_prefix_id :<%= singular_name %>
Enter fullscreen mode Exit fullscreen mode

If you were to generate a Book model, it would look like:

class Book
  has_prefix_id :book
end
Enter fullscreen mode Exit fullscreen mode

You can edit :book to :bk. Pick an abbreviation that resonates with your URL-appreciating customers.

Show them you care.

💖 💪 🙅 🚩
drnic
Dr Nic Williams

Posted on October 20, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related