Sluggi

Gem Version Build Status

Sluggi is a simple friendly_id-inspired slugging library for ActiveRecord models.

It provides basic slugs, slug history, and the ability to define multiple slug candidates.

Sluggi works with Rails 4.0+.

Install

Add this line to your Gemfile:

gem 'sluggi'

Add a string column named slug to any models you want to slug. You can generate a migration like so:

rails generate migration AddSlugToCats slug:string:uniq:index
rake db:migrate

To track slug history for any model, you must generate a migration to add the slugs table:

rails generate sluggi
rake db:migrate

Usage

Sluggi is Magic Free(tm). Each slugged model must:

  • Have a column named slug (see above).
  • Include the Sluggi::Slugged module
  • Override the slug_value method or the slug_candidates method.

Simple Slugged Model

Specify the slug value by defining #slug_value and #slug_value_changed?.

class Cat < ActiveRecord::Base
  include Sluggi::Slugged

  def slug_value
    name
  end

  def slug_value_changed?
    name_changed?
  end
end
cat = Cat.create(name: 'Tuxedo Stan')
cat.slug
=> 'tuxedo-stan'

cat.to_param
=> 'tuxedo-stan'

cat_path
=> 'cats/tuxedo-stan'

Cat.find_by_slug('tuxedo-stan')
=> cat

Model with Slugged History

To save slug history, include Sluggi::History. You get a slugs association. You can search for any slug in the history using .find_slug!.

class Cat < ActiveRecord::Base
  include Sluggi::Slugged
  include Sluggi::History

  def slug_value
    name
  end

  def slug_value_changed?
    name_changed?
  end
end
cat = Cat.create(name: 'Tuxedo Stan')
cat.slug
=> 'tuxedo-stan'

cat.name = 'Tuxedo Bob'
cat.save
cat.slug
=> 'tuxedo-bob'

# use .find_slug! to search slug history:

Cat.find_slug!('tuxedo-bob')
=> cat
Cat.find_slug!('tuxedo-stan')
=> cat

# plain finders will not search history:

Cat.find_by_slug('tuxedo-bob')
=> cat

Cat.find_by_slug('tuxedo-stan')
=> RecordNotFound

Model with Slug Candidates

Override #slug_candidates to define cascading candidate values for slugs. This is useful to avoid uniqueness conflicts.

class Cat < ActiveRecord::Base
  include Sluggi::Slugged

  def name_and_id
    "#{name}-#{id}"
  end

  # the first unused value in the list is used
  def slug_candidates
    [name, name_and_id]
  end

  def slug_value_changed?
    name_changed?
  end
end
cat = Cat.create(name: 'Tuxedo Stan')
cat.slug
=> 'tuxedo-stan'

cat_2 = Cat.create(name: 'Tuxedo Stan')
cat_2.slug
=> 'tuxedo-stan-2'
cat_2.id
=> 2

Alternatives