Last active
April 4, 2016 15:50
-
-
Save eiwi1101/c64a518032faad1d4cf73b940a58b63c to your computer and use it in GitHub Desktop.
Sluggable : An ActiveSupport Concern for generating URL slugs on a Model.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# === 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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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