The perfect Slug - URL

Permalinks must unambiguously identify a resource. However, they should also be “speaking”. This is important for SEO. In Ruby on Rails, the part of a URL that identifies a resource generally is just the ID of the database object. For SEO relevant resources, it makes sense to generate Slugs.
An obvious solution might be to include the Gem FriendlyID. It is very powerful. A little bit too extensive for many use cases. Especially since creating a proper implementation is very simple.
To guarantee the uniqueness of a Slug, it should contain the database ID of the object.
The following example is based on this approach.

The model

Blog posts are classic example for Slugs. Articles have a title and a text:

rails g model Article title:string content:text

In Ruby on Rails, the routes helper generate the URL from objects. They use the method #to_param. The implementation for ActiveRecord::Base#to_param returns the ID of the object.
For generating the Slug, this method has to be overwritten:

# app/models/article.rb
class Article < ApplicationRecord
  def to_param
    "#{id}-#{title.parameterize}"
  end
end

For the meaningful part of the Slug, the title is used in this example. String#parameterize replaces all spaces with a hyphen -, which is quite common.

The routes

The routes:

# config/routes.rb
Rails.application.routes.draw do
  resources :articles
end

The result can also be checked in the REPL (Rails console):

# Rails console
app.article_path Article.last
# => "/article/79-custom-validator-testen"

The controller

It is the advantage with this approach is that the controller looks exactly as if only the ID were passed as a parameter:

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def show
    @article = Article.find params[:id]
  end
end

This works because Ruby String#to_i only casts all numeric characters (from the Strings beginning to the first non-numeric character):

"79-custom-validator-testen".to_i
# => 79

Therefore it is not even necessary to persist the Slug.
However if there are reasons for persisting the Slug:

rails g migration add_slug_to_articles slug:string

then only the speaking part of the Slug (without the database ID) should be stored in any case:

# app/models/article.rb
class Article < ApplicationRecord
  before_create :set_slug

  def to_param
    "#{id}-#{slug}"
  end

  private

  def set_slug
    self.slug = title.parameterize
  end
end