Make descriptive URLs using friendly_id
This guide shows how to use the friendly_id gem on a posts scaffold so the title of the post is in the URL, and the history of the URL is remembered (so if the title of the post changes, old links will still work).
Setup and Installation
First make a new rails app and a posts scaffold
rails new myapp
rails g scaffold post title content:text
In this example, we’ll create the slugs (urls) from the post’s title
.
First add the most recent version of friendly_id to your Gemfile
gem 'friendly_id', '~> 5.4.0'
Create a migration to add a slug
column to the posts table, as well as a unique index on that column
rails g migration AddSlugToPosts slug:uniq
Then run
rails generate friendly_id
And finally
rails db:migrate
Using friendly_id in the controller
In the set_post
before_action, simply change
def set_post
@post = Post.find(params[:id])
end
To this
def set_post
@post = Post.friendly.find(params[:id])
end
Updating the model
Add this to your post model:
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
This tells friendly_id to use a post’s title
as the basis for its slug
.
Below that (also in the post model) place this which will update the slug when the title attribute changes:
def should_generate_new_friendly_id?
title_changed?
end
See more on should_generate_new_friendly_id?
here and here.
That’s it!
That’s all there is to it. You should now see the slug in the URL for a post. If you update the post’s title, the URL will change accordingly, and the old URL will still work!
Extra tips
If you have existing posts which need friendly ids created for them, you can do this to create them
Post.find_each(&:save)
Also, if you’re using uuid as the primary key on your posts table, you’ll have to also change this line in the friendly_id_slugs
table:
t.integer :sluggable_id, :null => false
to this
t.uuid :sluggable_id, :null => false