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
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
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
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
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
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 %>
If you were to generate a Book
model, it would look like:
class Book
has_prefix_id :book
end
You can edit :book
to :bk
. Pick an abbreviation that resonates with your URL-appreciating customers.
Show them you care.
Top comments (2)
I'm not sure if it's friendlier, but certainly interesting and easily hiding the monotonic id from the user. Does it use hashids under the hood?
Nice one, Nic.
I loved this. Hope it has some custom configurations like ‘friendly_id’ gem.
Anyway, a simpler and an interesting approach!