Back to home

Getting Started With The FriendlyID Gem In Rails 7 main image

Getting Started With The FriendlyID Gem In Rails 7

This post will crash-course through how you can use the Friendly ID gem in order to create routes that are more user-friendly.

Source code can be found here.

Prerequisites

  1. Basic familiarity with setting up a new Rails project.

Getting started

We will use Rails to initialize the project demo-friendly-id:

# Create a new rails project $ rails new demo-friendly-id $ cd demo-friendly-id # Generate controller and methods for our demonstration purposes $ bin/rails g controller documents $ bin/rails g model Document body:string title:string author:string

In the above commands, we also generated a basic model Document and a controller for those documents to illustrate the usage of Friendly ID.

First of all, let's demonstrate how things work without Friendly ID.

Updating routes

In order for our show route for a resource to work, we will need to enable that endpoint:

Rails.application.routes.draw do resources :documents, only: [:show] end

Creating some seed data

Update seeds from inside of the db/seeds.rb file to create four documents.

Document.create([ {title: "Star Wards", body: "Doing things", author: "Bill"}, {title: "Connect 4", body: "Cool article", author: "Bob"}, {title: "Star Wards", body: "Bob has an article with the same name as Bill!", author: "Bob"}, {title: "Friends From Afar", body: "Friends are forever", author: "Jane"} ])

Note that we are purposefully creating two documents titled Star Wards. This will demonstrate how we can enforce uniqueness with Friendly ID later when there are naming conflicts for our nominated ID key.

Update the controller

We now need to create our #show route handler in app/models/document.rb:

class DocumentsController < ApplicationController def show @document = Document.find(params[:id]) render json: @document end end

We will just return the resource as JSON for our demonstration.

Seeing how the app currently works

At this point, our code is ready to run a basic app.

Create and seed database, then start the Rails server:

# Database work $ bin/rails db:create db:migrate db:seed # Start the server $ bin/rails s

With the server running, we can grab any of the resources with their corresponding ID. Since we are auto-incrementing, this will be 1, 2, 3 or 4.

$ curl http://localhost:3000/documents/1 { "author": "Bill", "body": "Doing things", "created_at": "2022-03-12T00:28:48.391Z", "id": 1, "slug": "star-wards", "title": "Star Wards", "updated_at": "2022-03-12T00:28:48.391Z" }

At the moment, our URLs are not very user friendly if we were show this data on the frontend to clients. We can resolve this problem with Friendly ID.

Adding in Friendly ID

Add the following to your Gemfile:

gem 'friendly_id', '~> 5.4.0'

Run bundle in the command-line to install the gem.

Updating our model

We need to update our model to know what to reference for the slug in the model.

Update app/controllers/documents_controller.rb to the following:

class Document < ApplicationRecord extend FriendlyId friendly_id :slug_candidates, use: :slugged private # Try building a slug based on the following fields in # increasing order of specificity. def slug_candidates [ :title, %i[title author] ] end end

The slug_candidates method that we have written can be used to generate a slug if there is a collision. This helps us maintain control over what happens when we use something like the document name which is not unique.

Adding a slug to our document and generating the ID

Run the following to add a slug field to documents and migrate the changes.

# Required migration for field in DB $ bin/rails g migration AddSlugToDocuments slug:uniq $ bin/rails generate friendly_id $ bin/rails db:migrate

Update the controller to use Friendly ID

Friendly ID adds the friendly property to our model which we can insert to handle the param we pass the slug or database ID value to.

class DocumentsController < ApplicationController def show @document = Document.friendly.find(params[:id]) render json: @document end end

At this point, let's reset and reseed the database in order to generate the slugs and store them in our database.

# Reset, migrate and re-seed to generate the slugs $ bin/rails db:reset db:migrate db:seed

Testing our endpoint

Restart the server with bin/rails s

Now, both http GET localhost:3000/documents/1 and localhost:3000/documents/star-wards will return the first document.

$ curl http://localhost:3000/documents/1 { "author": "Bill", "body": "Doing things", "created_at": "2022-03-12T00:28:48.391Z", "id": 1, "slug": "star-wards", "title": "Star Wards", "updated_at": "2022-03-12T00:28:48.391Z" } $ curl http://localhost:3000/documents/star-wards { "author": "Bill", "body": "Doing things", "created_at": "2022-03-12T00:28:48.391Z", "id": 1, "slug": "star-wards", "title": "Star Wards", "updated_at": "2022-03-12T00:28:48.391Z" } # An example of our colliding document name going to the #{title}-#{author} format $ curl http://localhost:3000/documents/star-wards-bob { "author": "Bob", "body": "Bob has an article with the same name as Bill!", "created_at": "2022-03-12T00:28:48.403Z", "id": 3, "slug": "star-wards-bob", "title": "Star Wards", "updated_at": "2022-03-12T00:28:48.403Z" }

Awesome!

Summary

Today's post demonstrated how to use the Friendly ID gem in order to generate friendly slugs for our URLs.

Resources and further reading

Photo credit: pawel_czerwinski

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.