Our task today is to add unique slugs to our Company model on our Ruby on Rails app. The Company model has name and location properties, and we want to use those to create the slug. E.g. the company named Lugo Labs and based in London should have a slug, lugo-labs-london. We can then use that when showing the company page.
We could create the solution ourselves, but today we'll use the awesome FriendlyId to help us with it.
Installation
Installing FriendlyId is easy, we add it to our Gemfile:
# Gemfile
gem 'friendly_id'
and run:
bundle install
In order to generate slugs for our existing Company records, we need to tell our FriendlyId when to generate the slugs, by adding this private method:
# apps/models/company.rb
private
def should_generate_new_friendly_id?
slug.nil? || name_changed? || location_changed?
end
We're telling FriendlyId to generate new slugs when the slug is nil
or name, or location attributes have changed.
Migration
Let's add a migration for adding the slug attribute (using Rails 5):
rails g migration add_slug_to_companies slug
We could also generate the slugs as part of the migration, if we had existing company records.
class AddSlugToCompanies < ActiveRecord::Migration[5.0]
def up
add_column :companies, :slug, :string
add_index :companies, :slug, unique: true
say_with_time 'generating company slugs' do
Company.find_each(&:save)
end
end
def down
remove_column :companies, :slug, :string
end
end
Calling save
on the models triggers slug generation, so let's run the migration and see our slugs created:
rails db:migrate
We have also added a unique index on slug for good measure. FriendlyId also makes the slugs unique by default, appending a unique token to the next duplicated slug it finds. E.g. if we ever created another company Lugo Labs with location, London, its slug would be something like lugo-labs-london-127a893725532ahsr277.
Usage
In the Company model we add:
# apps/models/company.rb
extend FriendlyId
friendly_id %i(name location), use: :slugged
The friendly_id
macro has many options, here we're just telling it to use name and location to create slugs. You can see more info on this on the FriendlyId's README.
On the controller we can the enhancements provided by extending FriendlyId:
# app/controllers/companies_controller.rb
class CompaniesController < ApplicationController
def show
@company = Company.friendly.find(params[:id])
end
end
Considering that params[:id]
is the company slug, rather than company id, the friendly
method makes the finder to look up companies by slug, rather than id.
Conclusion
Now when we create new Company records, they will have unique slugs generated automatically. The companies URLs are all pretty with words in them, rather than the ids.
Happy coding!