lib/slugalicious.rb in slugalicious-2.0.0 vs lib/slugalicious.rb in slugalicious-2.1.0

- old
+ new

@@ -1,9 +1,9 @@ require 'slugalicious_generator' require 'stringex' -# Adds the @slugged@ method to an @ActiveRecord::Base@ subclass. You can then +# Adds the `slugged` method to an `ActiveRecord::Base` subclass. You can then # call this method to add slugging support to your model. See the # {ClassMethods#slugged} method for more details. # # @example Basic example of a slugged model # class Widget < ActiveRecord::Base @@ -45,11 +45,11 @@ # preceding the slug. # @return [ActiveRecord::Base, nil] The object with that slug, or `nil` if # not found. def find_from_slug(slug, scope=nil) - Slug.from_slug(self, scope, slug).first.try(:sluggable) + Slug.from_slug(self, scope, slug).first.try!(:sluggable) end # Locates a record from a given path, that consists of a slug and its scope, # as would appear in a URL path component. # @@ -65,66 +65,66 @@ end protected # Call this method to indicate that your model uses slugging. Pass a list of - # *slug generators*: either symbols (method names) or procs that return + # **slug generators**: either symbols (method names) or procs that return # strings. These strings will be used to generate the slug. You must pass at # least one generator. If you pass more than one, the first one that returns # a unique slug will be used. # # The generator does not need to sanitize or parameterize its output; the - # @:slugifier@ option can be used to override the default parameterization. + # `:slugifier` option can be used to override the default parameterization. # # In the event that no generator returns a unique slug, the slug returned by # the last generator will have the ID of the record appended to it. The ID - # and the slug will be separated by the @:id_separator@ option (semicolon by + # and the slug will be separated by the `:id_separator` option (semicolon by # default). _This_ slug is hopefully unique, because if not, an exception is # raised. # # Slugs are automatically generated before validation and updated when # necessary. # # h2. Scopes # - # You can scope your slugs to certain URL subpaths using the @:scope@ - # option. The @:scope:@ option takes a method name or a @Proc@ that, when + # You can scope your slugs to certain URL subpaths using the `:scope` + # option. The `:scope:` option takes a method name or a `Proc` that, when # run, returns a string that scopes the uniqueness constraint of a slug. # Rather than being globally unique, the slug must only be unique among # other slugs that share the same scope. # - # *Important note:* The method or @Proc@ that you use for the @:scope@ + # **Important note:** The method or `Proc` that you use for the `:scope` # option should return the portion of the URL preceding the slug, _slash - # included_. Let's say you have slugged your @User@ model's @login@ field, + # included_. Let's say you have slugged your `User` model's `login` field, # and you have two scopes: customers and merchants. In that case, you would - # want the @:scope@ method/proc to return either "clients/" or "merchants/". + # want the `:scope` method/proc to return either "clients/" or "merchants/". # - # The string returned by the @:scope@ option will be used to build the full - # URL to an object. If you have a client @User@ with login "fancylad", a - # call to @to_param@ will return "clients/fancyland". The scope portion of + # The string returned by the `:scope` option will be used to build the full + # URL to an object. If you have a client `User` with login "fancylad", a + # call to `to_param` will return "clients/fancyland". The scope portion of # that URL path is used un-sanitized, un-escaped, and un-processed. It is # therefore up to _you_ to ensure your scopes are valid URL strings, using - # say @String#to_url@ (included as part of this gem). + # say `String#to_url` (included as part of this gem). # # @overload slugged(generator, ..., options={}) - # @param [Proc, Symbol] generator If it's a @Symbol@, indicates a method - # that will be called that will return a @String@ to be used for the + # @param [Proc, Symbol] generator If it's a `Symbol`, indicates a method + # that will be called that will return a `String` to be used for the # slug. # @param [Hash] options Additonal options that control slug generation. # @option options [Proc] :slugifier (&:to_url) A proc that, when given a # string, produces a URL-safe slugged version of that string. # @option options [String] :id_separator (';') A separator to be used in # the "last-resort" slug between the slug and the model ID. This should # be an URL-safe character that would never be produced by your # slugifier. - # @option options [Symbol, Proc] :scope A method name or @Proc@ to run + # @option options [Symbol, Proc] :scope A method name or `Proc` to run # (receives the object being slugged) that returns a string. Slugs must # be unique across all objects for which this method/proc returns the # same value. If not provided, slugs must be globally unique for this # model. The string returned should be equal to the portion of the URL # path that precedes the slug. - # @option options [Array<String>, String] :blacklist ([ 'new', 'edit', 'delete' ]) + # @option options [Array<String>, String] :blacklist ([ 'new', 'edit', 'delete', 'destroy' ]) # A list of slugs that are disallowed. You would use this to prevent # slugs from sharing the same name as actions in your resource # controller. # @raise [ArgumentError] If no generators are provided. @@ -143,43 +143,43 @@ elsif options[:scope].kind_of?(Proc) then options[:scope] elsif options[:scope] then raise ArgumentError, ":scope must be a symbol or proc" end - self._slug_blacklist = Array.wrap(options[:blacklist] || %w( new edit delete )) + self._slug_blacklist = Array.wrap(options[:blacklist] || %w( new edit delete destroy )) after_save :make_slug end end def slug_object - slugs.loaded? ? slugs.detect(&:active) : slugs.active.first + slugs.loaded? ? slugs.detect(&:active?) : slugs.active.first end private :slug_object - # @return [String, nil] The slug for this object, or @nil@ if none has been + # @return [String, nil] The slug for this object, or `nil` if none has been # assigned. def slug Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug") do - slug_object.try(:slug) + slug_object.try!(:slug) end end # @return [String, nil] The full slug and path for this object, with scope - # included, or @nil@ if none has been assigned. + # included, or `nil` if none has been assigned. 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). + # @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) @active_slug ||= begin slug = if slugs.loaded? then slugs.detect { |s| s.slug.downcase == slug.downcase } @@ -198,11 +198,11 @@ def make_slug slugs_in_use = if slugs.loaded? then slugs.map(&:slug) else - slugs.select(:slug).all.map(&:slug) + slugs.select(:slug).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. @@ -230,21 +230,22 @@ # 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 + taken_slug_objects = scope # 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)) + scope: self.class._slug_scope.try!(:call, self)) + slugs(true) end @active_slug = nil end end