class Mongoid::Slug::UniqueSlug

Constants

MUTEX_FOR_SLUG

Attributes

_slug[R]
model[R]

Public Class Methods

new(model) click to toggle source
# File lib/mongoid/slug/unique_slug.rb, line 68
def initialize model
  @model = model
  @_slug = ""
  @state = nil
end

Public Instance Methods

find_unique(attempt = nil) click to toggle source
# File lib/mongoid/slug/unique_slug.rb, line 78
def find_unique attempt = nil
  MUTEX_FOR_SLUG.synchronize do
    @_slug = if attempt
      attempt.to_url
    else
      url_builder.call(model)
    end
    # Regular expression that matches slug, slug-1, ... slug-n
    # If slug_name field was indexed, MongoDB will utilize that
    # index to match /^.../ pattern.
    pattern = /^#{Regexp.escape(@_slug)}(?:-(\d+))?$/
  
    where_hash = {}
    where_hash[:_slugs.all] = [pattern]
    where_hash[:_id.ne]     = model._id
  
    if (scope = slug_scope) && reflect_on_association(scope).nil?
      # scope is not an association, so it's scoped to a local field
      # (e.g. an association id in a denormalized db design)
      where_hash[scope] = model.try(:read_attribute, scope)
    end
  
    if by_model_type == true
      where_hash[:_type] = model.try(:read_attribute, :_type)
    end
  
    @state = SlugState.new @_slug, uniqueness_scope.unscoped.where(where_hash), pattern
  
    # do not allow a slug that can be interpreted as the current document id
    @state.include_slug unless model.class.look_like_slugs?([@_slug])
  
    # make sure that the slug is not equal to a reserved word
    @state.include_slug if reserved_words.any? { |word| word === @_slug }
  
    # only look for a new unique slug if the existing slugs contains the current slug
    # - e.g if the slug 'foo-2' is taken, but 'foo' is available, the user can use 'foo'.
    if @state.slug_included?
      highest = @state.highest_existing_counter
      @_slug += "-#{highest.succ}"
    end
    @_slug
  end
end
metadata() click to toggle source
# File lib/mongoid/slug/unique_slug.rb, line 74
def metadata
  @model.respond_to?(:relation_metadata) ? @model.relation_metadata : @model.metadata
end
uniqueness_scope() click to toggle source
# File lib/mongoid/slug/unique_slug.rb, line 122
def uniqueness_scope

  if slug_scope &&
      metadata = reflect_on_association(slug_scope)

    parent = model.send(metadata.name)

    # Make sure doc is actually associated with something, and that
    # some referenced docs have been persisted to the parent
    #
    # TODO: we need better reflection for reference associations,
    # like association_name instead of forcing collection_name here
    # -- maybe in the forthcoming Mongoid refactorings?
    inverse = metadata.inverse_of || collection_name
    return parent.respond_to?(inverse) ? parent.send(inverse) : model.class
  end

  if embedded?
    parent_metadata = reflect_on_all_associations(:embedded_in)[0]
    return model._parent.send(parent_metadata.inverse_of || self.metadata.name)
  end

  #unless embedded or slug scope, return the deepest document superclass
  appropriate_class = model.class
  while appropriate_class.superclass.include?(Mongoid::Document)
    appropriate_class = appropriate_class.superclass
  end
  appropriate_class
end