Skip to content

Instantly share code, notes, and snippets.

@loopj
Created April 6, 2013 22:24
Show Gist options
  • Select an option

  • Save loopj/5327885 to your computer and use it in GitHub Desktop.

Select an option

Save loopj/5327885 to your computer and use it in GitHub Desktop.
module SimpleMongoidSlug
extend ActiveSupport::Concern
included do
cattr_accessor :slug_scope, :slug_field
end
module ClassMethods
def slug(*field)
options = field.extract_options!
self.slug_scope = options[:scope]
self.slug_field = field.first
# Add the slug field to the model
field(:slug, type: String)
# Add index info to the model
if slug_scope
scope_key = (metadata = self.reflect_on_association(slug_scope)) ? metadata.key : slug_scope
index({scope_key => 1, slug: 1}, {unique: true, sparse: true})
else
index({slug: 1}, {unique: true, sparse: true})
end
# Generate slugs automatically
set_callback :validation, :before, :build_slug, if: :slug_should_be_rebuilt?
end
end
def slug_should_be_rebuilt?
new_record? || attribute_changed?(self.slug_field.to_s)
end
def build_slug
self.slug = generate_unique_slug
end
def generate_unique_slug
# Start with a base slug
unique_slug = self.send(self.slug_field).parameterize
# Find all existing blah, blah-n slugs
conditions = {}
conditions[:slug] = /^#{Regexp.escape(unique_slug)}(?:-(\d+))?$/
conditions[:_id.ne] = self._id
existing_slugs = uniqueness_scope.unscoped.where(conditions).only(:slug).map &:slug
# Add suffix until unique
slug_suffix = 1
while existing_slugs.include?(unique_slug)
unique_slug = "#{unique_slug}-#{slug_suffix}"
slug_suffix += 1
end
unique_slug
end
def uniqueness_scope
if slug_scope
metadata = reflect_on_association(slug_scope)
parent = self.send(metadata.name)
inverse = metadata.inverse_of || collection_name
parent.respond_to?(inverse) ? parent.send(inverse) : self.class
else
self.class
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment