lib/mongoid/urls.rb
require 'mongoid'
module Mongoid
# Creates friendly urls for mongoid models!
module Urls
extend ActiveSupport::Concern
included do
cattr_accessor :reserved_words,
:url_simple,
# :url_scope,
:url_keys
end
# Methods avaiable at the model
module ClassMethods
#
# The #url
#
# url :title
#
# :simple -> Only one url per instance
# :reserve -> Defaults to %w( new edit ) + I18n.locales
#
def url(*args)
options = args.extract_options!
raise 'Only one #url per model!' if url_keys
self.url_keys = args # .first.to_s
self.url_simple = options[:simple]
create_url_fields
create_url_validations(options)
end
def create_url_validations(options)
before_validation :create_urls
reserve = Set.new(%w(new edit)) + (options[:reserved] || [])
reserve << I18n.available_locales if Object.const_defined?('I18n')
self.reserved_words = reserve.flatten
validates :url, uniqueness: true, presence: true,
format: { with: /[a-z\d-]+/ }
end
def find_url(u)
find_by(url: u) || (!url_simple && find_by(urls: u))
rescue Mongoid::Errors::DocumentNotFound
nil
end
alias find_by_url find_url
private
def create_url_fields
field :url, type: String
index({ url: 1 }, unique: true)
define_method('url=') do |val|
self[:url] = val.parameterize
end
return if url_simple
field :urls, type: Array, default: []
index(urls: 1)
end
end # ClassMethods
def to_param
url
end
# Gets a new url.
# Go each arg/key one by one, don't join'em.
def new_url
url_keys.each do |key|
next if (val = send(key)).blank?
url = val.to_s.parameterize
if (dup = self.class.find_url(url))
next if dup.id != id
end
return url
end; nil
end
protected
def validate_url(slug)
return unless reserved_words.include?(slug)
errors.add(:url, :reserved)
end
def create_urls
return unless (slug = new_url)
validate_url(slug)
self.url = slug
return if url_simple
urls << slug
urls.uniq!
end
end # Urls
end # Mongoid