friendly id url example

1. Minimal setup - no additional column

bundle add friendly_id
# will install the gem
#app/models/inbox.rb
  extend FriendlyId
  friendly_id :name
#app/controllers/inboxes_controller.rb
  def set_inbox
--    @inbox = Inbox.find(params[:id])
++    @inbox = Inbox.friendly.find(params[:id])
  end

2. :finders - always add it!

#app/models/inbox.rb
  extend FriendlyId
--  friendly_id :name
++  friendly_id :name, use: [:finders]
#app/controllers/inboxes_controller.rb
  def set_inbox
++    @inbox = Inbox.find(params[:id])
--    @inbox = Inbox.friendly.find(params[:id])
  end

2. :slugged - always add it too!

rails g migration AddSlugToInboxes slug:uniq
# will add column that will store the friendly_id
#app/models/inbox.rb
  extend FriendlyId
--  friendly_id :name, use: [:finders]
++  friendly_id :name, use: [:finders, :slugged]
Inbox.find_each(&:save)
# update the slug for all existing records
# in the above case, slug = name
  • 2.1. you can create non-attribute slug names, like randoms
#app/models/inbox.rb
  extend FriendlyId
--  friendly_id :name, use: [:finders, :slugged]
++  friendly_id :random_hex, use: [:finders, :slugged]
++  def random_hex
++    SecureRandom.hex
++  end
  • 2.2. candidates - use longer option if shorer one is taken
#app/models/inbox.rb
  extend FriendlyId
--  friendly_id :name, use: [:finders, :slugged]
++  friendly_id :slug_candidates, use: [:finders, :slugged]
++   def slug_candidates
++     [
++       :name,
++       [:name, :description],
++       [:name, :descroption, :created_at]
++     ]
++   end

4. Conditionally auto-update slug

#app/models/inbox.rb
  extend FriendlyId
  friendly_id :name
++  def should_generate_new_friendly_id?
++    name_changed?
++  end

NOTE: this can be a bit buggy:

  • go to edit
  • change name to something invalid
  • submit, get normal validation error
  • change name to something valid
  • submit, get ActiveRecord::RecordNotFound (can't find record with friendly id: "ger"):

5. :history. Customizing friendly_id.rb

All the new slugs will be saved in a separate database table -> you will be able to access records via their OLD URLs!

#app/models/inbox.rb
  extend FriendlyId
--  friendly_id :name, use: [:finders, :slugged]
++  friendly_id :name, use: [:finders, :slugged, :history]
rails generate friendly_id
# create db/migrate/20211105220542_create_friendly_id_slugs.rb
# create config/initializers/friendly_id.rb