Module: Mongoid::LocalizedSlug::ClassMethods

Defined in:
lib/mongoid/localized_slug.rb

Instance Method Summary collapse

Instance Method Details

#find_unique_slug_for(desired_slug, options = {}) ⇒ String

Finds a unique slug, were specified string used to generate a slug.

Returned slug will the same as the specified string when there are no duplicates.

generate the slug, if the class creates scoped slugs. Defaults to ‘nil`. generated for. This option overrides `:scope`, as the scope can now be extracted from the model. Defaults to `nil`.

Parameters:

  • desired_slug (String)
  • options (Hash) (defaults to: {})
  • options (Symbol) (defaults to: {})

    :scope The scope that should be used to

  • options (Constant) (defaults to: {})

    :model The model that the slug should be

Returns:

  • (String)

    A unique slug



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/mongoid/localized_slug.rb', line 99

def find_unique_slug_for(desired_slug, options = {})
  excluded_id = options[:model]._id if options[:model]

  slug = desired_slug.to_url

  # 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[slug_name] = pattern
  where_hash[:_id.ne]   = excluded_id if excluded_id

  existing_slugs_criteria =
    only(slug_name).
    where(where_hash)

  existing_slugs = []

  existing_slugs_criteria.map do |doc|
    if doc.slug.is_a?(Array)
      doc.slug.each do |s|
        existing_slugs << s if pattern.match(s)
      end
    else
      existing_slugs << doc.slug if pattern.match(doc.slug)
    end
  end

  # Do not allow BSON::ObjectIds as slugs
  existing_slugs << slug if BSON::ObjectId.legal?(slug)

  if reserved_words_in_slug.any? { |word| word === slug }
    existing_slugs << slug
  end

  if existing_slugs.count > 0
    # Sort the existing_slugs in increasing order by comparing the
    # suffix numbers:
    # slug, slug-1, slug-2, ..., slug-n
    existing_slugs.sort! do |a, b|
      (pattern.match(a)[1] || -1).to_i <=>
      (pattern.match(b)[1] || -1).to_i
    end
    max = existing_slugs.last.match(/-(\d+)$/).try(:[], 1).to_i

    slug += "-#{max + 1}"
  end

  slug
end

#slug(*fields) ⇒ Object #slug(*field, options) ⇒ Object

Examples:

A custom builder

class Person
  include Mongoid::Document
  include Mongoid::LocalizedSlug

  field :name, localize: true

  slug  :name, :index => true
end

Overloads:

  • #slug(*fields) ⇒ Object

    Sets one ore more fields as source of slug.

    Parameters:

    • The (Symbol)

      fields the slug should be based on.

  • #slug(*field, options) ⇒ Object

    Sets one ore more fields as source of slug. slug. Defaults to ‘slug`. on the slug field. Defaults to `false`. immutable. Defaults to `false`.

    Parameters:

    • The (Symbol)

      the slug should be based on.

    • options (Hash)
    • options (String)

      :as The name of the field that stores the

    • options (Boolean)

      :index Whether an index should be defined

    • options (Boolean)

      :permanent Whether the slug should be

    • options (Array)

      :reserve` A list of reserved slugs



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/mongoid/localized_slug.rb', line 40

def slug(*field_and_options)
  options = field_and_options.extract_options!

  self.reserved_words_in_slug = options[:reserve] || []
  self.slug_name              = options[:as] || :slug
  self.slugged_attribute      = field_and_options.first.to_s

  field slug_name, :type => Array, :default => []
  field "#{slug_name}_translations", :type => Hash, :default => {}

  unless slug_name == :slug
    alias_attribute :slug, slug_name
    alias_attribute :slug_translations, "#{slug_name}_translations"
  end

  if options[:index]
    index slug_name, :unique => true
  end

  set_callback options[:permanent] ? :create : :save, :before do |doc|
    doc.build_slug if doc.slug_should_be_rebuilt?
  end

  # Build a finder for slug.
  #
  # Defaults to `find_by_slug`.
  instance_eval <<-CODE
    def self.find_by_#{slug_name}(slug)
      where(slug_name => slug).first
    end

    def self.find_by_#{slug_name}!(slug)
      self.find_by_#{slug_name}(slug) ||
        raise(Mongoid::Errors::DocumentNotFound.new self, slug)
    end
  CODE

  # Build a scope based on the slug name.
  #
  # Defaults to `by_slug`.
  scope "by_#{slug_name}".to_sym, lambda { |slug|
    where(slug_name => slug)
  }
end