ryanwhocodes Feb 3, 2018 · 3 min read

How to Create User Friendly URLs in Ruby on Rails

A Ruby on Rails guide to creating user-friendly URLs with slugs instead of record IDs.

When you browse the web, you usually see URLs that are descriptive of the page you are going to. For example Medium’s blog post URLs are formed by the title of the post. Using Ruby on Rails resources for your routing defaults to finding models by their ids. This post will show you how to change this to route and find a model’s URL.

Contents

What are pretty URLs?

A slug is a name given to a URL of a page, which derives from the publishing and printing industries. There is no single best way of routing on websites. Some use full words and sentences, some use an id, some use a combination of both. For example, Medium puts the id at the end of the URL slug.

In this article you will learn to change an id-based URL like this:

https://medium.freecodecamp.org/67c631475a94

… to a more verbose URL like this:

https://medium.freecodecamp.org/custom-urls-in-ruby-on-rails-use-descriptive-slugs-instead-of-ids-67c631475a94

Generate the pretty URL strings

It’s useful to have a method to use across your app to ensure that URLs are formatted the same way and won’t have issues when browsers try to display them. One way to do this is by including it in your base record class:

# app/models/application_record.rb

module ApplicationRecord
  def to_slug(string)
    string.parameterize.truncate(80, omission: '')
  end
end

This uses the Rails methods parameterize (to replace special characters with hyphens) and truncate (to set a max length for the slug).

Add slugs to your records

Add the field to your records by first running a migration:

rails generate migration AddSlugToPost slug:string
rails rake db:migrate

Then ensure that the create and update include the slug field.

Post.create(slug: to_slug(name))

If you’ve already created records, you can run a task to add the slugs in, such as the following (assuming you want a slug based on a name field).

class Post < ApplicationRecord
  def self.add_slugs
    update(slug: to_slug(name))
  end
end

Then in the terminal, run:

rails console
Post.add_slugs

Override to_param

Rails’ default to_param method returns the id of the record. If you override this, then when you add a record to a view, such as…

<%= link_to "View post", @post %>

… it will route to post/my-post-url-slug rather than the id, for example post/1.

class Post < ApplicationRecord
  def to_param
    slug
  end
end

Performance issues: Computers find searching by ids quicker than strings, so there may be a performance impact of using the slug to find the records. There are alternative options, such as Stack Overflow, including the id then the slug after that.

Set routes to use slugs

Next up is updating config/routes.rb in your Rails project. The resources helper methods will by default use id. You can override this by telling it to use slugs instead.

resources :post, param: :slug

Find by slugs in your controllers

Almost there… Lastly, you need to tell your controllers to find records by slug rather than id. Rails will interpret the field you specify in the name of a find_by method, so you can use find_by as a way of searching by a slug.

class PostController < ApplicationController
  def show
    @post = find_by(slug: params[:slug])
  end
end

Enjoy the pretty URLs

Now when you visit pages in your webpage, you should see the slug describing the page.

Find out more

Learning how to configure and define pretty URLs can make it easier to discover and navigate content on your website.

The Ruby on Rails Guides are a good place to learn more about routing and URLs, and my other Ruby on Rails posts cover other areas of this web app framework.