Skip to content

Instantly share code, notes, and snippets.

@eiwi1101
Last active April 4, 2016 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eiwi1101/c64a518032faad1d4cf73b940a58b63c to your computer and use it in GitHub Desktop.
Save eiwi1101/c64a518032faad1d4cf73b940a58b63c to your computer and use it in GitHub Desktop.
Sluggable : An ActiveSupport Concern for generating URL slugs on a Model.
# === Table Schema
#
# id: integer
# title: string
# body: string
# author_id: integer
#
class Post < ActiveRecord::Base
include Sluggable
belongs_to :author
slugify :title, scope: :author
end
# Slug is automagically generated before Validation:
Post.new(title: 'Something Awesome')
Post.slug #=> nil
Post.valid? #=> true
Post.slug #=> 'something-awesome'
Post.save
# Slug is generated unique in scope (here, scope is nil author):
Post.create(title: 'Something Awesome')
Post.slug #=> 'something-awesome-1'
# Slug can be manually set and this concern won't do much of anything:
Post.create(title: 'Something Awesome', slug: 'rick-astley')
module Sluggable
extend ActiveSupport::Concern
included do
before_validation :generate_slug
class_attribute :slug_options
class_attribute :slug_source
self.slug_source = :name
self.slug_options = {}
end
def to_param
self.slug
end
module ClassMethods
def slugify(source_column, options = {})
self.slug_source = source_column
self.slug_options = options
end
end
private
def generate_slug
return true unless self.slug.blank?
slug_scope = slug_options[:scope] ? {slug_options[:scope] => self.send(slug_options[:scope])} : '1=1'
count = 0
begin
self.slug = to_slug(self.send(slug_source), count > 0 ? count : nil)
count += 1
end while self.class.where(slug_scope).exists?(slug: self.slug)
true
end
def to_slug(string, tail=nil)
return if string.nil?
slug = string.downcase.gsub(/[^a-z0-9-]+/, '-').gsub(/^-+|-+$/, '')
slug = [slug, tail].join('-') if tail
slug
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment