lib/slugalicious.rb in slugalicious-1.2.0 vs lib/slugalicious.rb in slugalicious-1.2.1
- old
+ new
@@ -16,14 +16,12 @@
# The maximum length of a slug.
MAX_SLUG_LENGTH = 126
included do
- extend ActiveSupport::Memoizable
- memoize :slug, :active_slug?
alias_method :to_param, :slug_with_path
- has_many :slugs, as: :sluggable
+ has_many :slugs, as: :sluggable, dependent: :delete_all
end
# Methods added to the class when this module is included.
module ClassMethods
@@ -141,43 +139,40 @@
after_save :make_slug
end
end
- # Methods added to instances when this module is included.
+ def slug_object
+ slugs.loaded? ? slugs.detect(&:active) : slugs.active.first
+ end
+ private :slug_object
- module InstanceMethods
+ # @return [String, nil] The slug for this object, or @nil@ if none has been
+ # assigned.
- def slug_object
- slugs.loaded? ? slugs.detect(&:active) : slugs.active.first
+ def slug
+ Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug") do
+ slug_object.try(:slug)
end
- private :slug_object
+ end
- # @return [String, nil] The slug for this object, or @nil@ if none has been
- # assigned.
+ # @return [String, nil] The full slug and path for this object, with scope
+ # included, or @nil@ if none has been assigned.
- def slug
- Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug") do
- slug_object.try(:slug)
- end
+ def slug_with_path
+ Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug_with_path") do
+ slug_object ? (slug_object.scope.to_s + slug_object.slug) : nil
end
+ end
- # @return [String, nil] The full slug and path for this object, with scope
- # included, or @nil@ if none has been assigned.
+ # @param [String] slug A slug for this object.
+ # @return [true, false, nil] @true@ if the slug is the currently active one
+ # (should not redirect), @false@ if it's inactive (should redirect), and
+ # @nil@ if it's not a known slug for the object (should 404).
- def slug_with_path
- Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug_with_path") do
- slug_object ? (slug_object.scope.to_s + slug_object.slug) : nil
- end
- end
-
- # @param [String] slug A slug for this object.
- # @return [true, false, nil] @true@ if the slug is the currently active one
- # (should not redirect), @false@ if it's inactive (should redirect), and
- # @nil@ if it's not a known slug for the object (should 404).
-
- def active_slug?(slug)
+ def active_slug?(slug)
+ @active_slug ||= begin
slug = if slugs.loaded? then
slugs.detect { |s| s.slug.downcase == slug.downcase }
else
slugs.where(slug: slug).first
end
@@ -185,62 +180,62 @@
slug.active?
else
nil
end
end
+ end
- private
+ private
- def make_slug
- slugs_in_use = if slugs.loaded? then
- slugs.map(&:slug)
- else
- slugs.select(:slug).all.map(&:slug)
- end
+ def make_slug
+ slugs_in_use = if slugs.loaded? then
+ slugs.map(&:slug)
+ else
+ slugs.select(:slug).all.map(&:slug)
+ end
- # grab a list of all potential slugs derived from the generators
- potential_slugs = self.class._slug_procs.map { |slug_proc| slug_proc[self] }.
- compact.
- map { |slug| self.class._slugifier[slug] }.
- map { |slug| slug[0, MAX_SLUG_LENGTH] }
- raise "All slug generators returned nil for #{self.inspect}" if potential_slugs.empty?
- # include the last-resort slug, trimmed for length
- last_resort_append = "#{self.class._slug_id_separator}#{id}"
- potential_slugs << "#{potential_slugs.first[0, [ 1, MAX_SLUG_LENGTH - last_resort_append.length ].max]}#{last_resort_append}"[0, MAX_SLUG_LENGTH]
- # subtract out blacklisted slugs
- potential_slugs -= self.class._slug_blacklist
-
- # if one of these slugs is already in use, we don't need to change the slug
- # instead, activate the one of highest prioirty and we're done
- valid_slugs_in_use = potential_slugs & slugs_in_use
- unless valid_slugs_in_use.empty?
- Slug.transaction do
- slugs.update_all(active: false)
- slugs.where(slug: valid_slugs_in_use.first).update_all(active: true)
- end
- return
- end
-
+ # grab a list of all potential slugs derived from the generators
+ potential_slugs = self.class._slug_procs.map { |slug_proc| slug_proc[self] }.
+ compact.
+ map { |slug| self.class._slugifier[slug] }.
+ map { |slug| slug[0, MAX_SLUG_LENGTH] }
+ raise "All slug generators returned nil for #{self.inspect}" if potential_slugs.empty?
+ # include the last-resort slug, trimmed for length
+ last_resort_append = "#{self.class._slug_id_separator}#{id}"
+ potential_slugs << "#{potential_slugs.first[0, [ 1, MAX_SLUG_LENGTH - last_resort_append.length ].max]}#{last_resort_append}"[0, MAX_SLUG_LENGTH]
+ # subtract out blacklisted slugs
+ potential_slugs -= self.class._slug_blacklist
+
+ # if one of these slugs is already in use, we don't need to change the slug
+ # instead, activate the one of highest prioirty and we're done
+ valid_slugs_in_use = potential_slugs & slugs_in_use
+ unless valid_slugs_in_use.empty?
Slug.transaction do
- # grab a list of all the slugs we can't use
- scope = Slug.select(:slug).where(sluggable_type: self.class.to_s, slug: potential_slugs)
- if self.class._slug_scope then
- scope = scope.where(scope: self.class._slug_scope[self])
- end
- taken_slug_objects = scope.all
-
- # subtract them out from all the potential slugs to make the available slugs
- available_slugs = potential_slugs - taken_slug_objects.map(&:slug)
- # no slugs available? nothing much else we can do
- raise "Couldn't find a slug for #{self.inspect}; tried #{potential_slugs.join(', ')}" if available_slugs.empty?
-
slugs.update_all(active: false)
- Slug.create!(sluggable: self,
- slug: available_slugs.first,
- active: true,
- scope: self.class._slug_scope.try(:call, self))
+ slugs.where(slug: valid_slugs_in_use.first).update_all(active: true)
end
+ return
+ end
- unmemoize_all
+ Slug.transaction do
+ # grab a list of all the slugs we can't use
+ scope = Slug.select(:slug).where(sluggable_type: self.class.to_s, slug: potential_slugs)
+ if self.class._slug_scope then
+ scope = scope.where(scope: self.class._slug_scope[self])
+ end
+ taken_slug_objects = scope.all
+
+ # subtract them out from all the potential slugs to make the available slugs
+ available_slugs = potential_slugs - taken_slug_objects.map(&:slug)
+ # no slugs available? nothing much else we can do
+ raise "Couldn't find a slug for #{self.inspect}; tried #{potential_slugs.join(', ')}" if available_slugs.empty?
+
+ slugs.update_all(active: false)
+ Slug.create!(sluggable: self,
+ slug: available_slugs.first,
+ active: true,
+ scope: self.class._slug_scope.try(:call, self))
end
+
+ @active_slug = nil
end
end