Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Worked on documentation.

  • Loading branch information...
commit ce7eb3c51be7c7b994b7dfeb9f107bfd9f008bcc 1 parent 1b2e8a7
@norman authored
View
2  .yardopts
@@ -0,0 +1,2 @@
+--files=*.md
+--protected
View
116 Guide.md
@@ -17,69 +17,6 @@ FriendlyId will always remain compatible with the current release of Rails, and
at least one stable release behind. That means that support for 3.0.x will not be
dropped until a stable release of 3.2 is out, or possibly longer.
-### Using a Custom Method to Generate the Slug Text
-
-FriendlyId can use either a column or a method to generate the slug text for
-your model:
-
- class City < ActiveRecord::Base
- extend FriendlyId
- belongs_to :country
- friendly_id :name_and_country, :use => :slugged
-
- def name_and_country
- #{name} #{country.name}
- end
-
- end
-
- @country = Country.create(:name => "Argentina")
- @city = City.create(:name => "Buenos Aires", :country => @country)
- @city.friendly_id # will be "buenos-aires-argentina"
-
-One word of caution: in the example above, if the country's name were updated,
-say, to "Argentine Republic", the city's friendly_id would not be
-automatically updated. For this reason, it's a good idea to avoid using
-frequently-updated relations as a part of the friendly_id.
-
-## Using a Custom Method to Process the Slug Text
-
-If the built-in slug text handling options don't work for your application,
-you can override the `normalize_friendly_id` method in your model class in
-order to fine-tune the output:
-
- class City < ActiveRecord::Base
- extend FriendlyId
- friendly_id :whatever, :use => :slugged
-
- def normalize_friendly_id(text)
- my_text_modifier_method(text)
- end
-
- end
-
-The `normalize_friendly_id` method takes a single argument and receives an
-instance of {FriendlyId::SlugString}, a class which wraps a regular Ruby string
-with additional formatting options.
-
-### Converting non-Latin characters to ASCII with Babosa
-
-Babosa offers the ability to idiomatically transliterate non-ASCII characters
-to ASCII:
-
- "Jürgen".to_slug.normalize! #=> "Jurgen"
- "Jürgen".to_slug.normalize! :transliterate => :german #=> "Juergen"
-
-Using Babosa with FriendlyId is a simple matter of installing and requiring
-the `babosa` gem, and overriding the `normalize_friendly_id` method in your
-model:
-
- class City < ActiveRecord::Base
- def normalize_friendly_id(text)
- text.slug.normalize!
- end
- end
-
## Redirecting to the Current Friendly URL
FriendlyId can maintain a history of your record's older slugs, so if your
@@ -111,45 +48,6 @@ record's friendly_id changes, your URL's won't break.
end
end
-## Non-unique Slugs
-
-FriendlyId will append a arbitrary number to the end of the id to keep it
-unique if necessary:
-
- /posts/new-version-released
- /posts/new-version-released--2
- /posts/new-version-released--3
- ...
- etc.
-
-Note that the number is preceded by "--" rather than "-" to distinguish it from
-the rest of the slug. This is important to enable having slugs like:
-
- /cars/peugeot-206
- /cars/peugeot-206--2
-
-You can configure the separator string used by your model by setting the
-`:sequence_separator` option in `friendly_id`:
-
- friendly_id :title, :use => :slugged, :sequence_separator => ":"
-
-You can also override the default used in
-{FriendlyId::Configuration::DEFAULTS} to set the value for any model using
-FriendlyId. If you change this value in an existing application, be sure to
-{file:Guide.md#regenerating_slugs regenerate the slugs} afterwards.
-
-For reasons I hope are obvious, you can't change this value to "-". If you try,
-FriendlyId will raise an error.
-
-## Reserved Words
-
-When you use slugs, FriendlyId adds a validation to avoid using "new" and
-"index" as slugs. You can control the default reserved words by changing the
-value in `FriendlyId::Configuration::DEFAULTS[:reserved_words]`.
-
-## Scoped Slugs
-
-
# Misc tips
## Default Scopes
@@ -177,17 +75,3 @@ column.
These benchmarks can give you an idea of FriendlyId's impact on the
performance of your application. Of course your results may vary.
- activerecord (3.0.9)
- ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0]
- friendly_id (4.0.0.beta1)
- sqlite3 (1.3.3) gem
- sqlite3 3.6.12 in-memory database
-
-
- user system total real
- find (without FriendlyId) 0.300000 0.000000 0.300000 ( 0.306729)
- find (in-table slug) 0.350000 0.000000 0.350000 ( 0.351760)
- find (external slug) 3.320000 0.000000 3.320000 ( 3.326749)
- insert (without FriendlyId) 0.810000 0.010000 0.820000 ( 0.810513)
- insert (in-table-slug) 1.740000 0.000000 1.740000 ( 1.743511)
- insert (external slug) 3.540000 0.010000 3.550000 ( 3.544898)
View
6 README.md
@@ -70,6 +70,12 @@ FriendlyId is compatible with Active Record **3.0** and **3.1**.
GET http://localhost:3000/users/joe-schmoe
+## Benchmarks
+
+The latest benchmarks for FriendlyId are maintained
+[here](https://gist.github.com/1129745).
+
+
## Bugs
Please report them on the [Github issue
View
2  Rakefile
@@ -45,7 +45,7 @@ task :gem do
end
task :yard do
- puts %x{bundle exec yard doc --files=*.md}
+ puts %x{bundle exec yard}
end
task :bench do
View
2  lib/friendly_id.rb
@@ -94,7 +94,7 @@ module FriendlyId
# Previous versions of FriendlyId simply patched ActiveRecord::Base, but this
# version tries to be less invasive.
#
- # In addition to adding {FriendlyId::Base.friendly_id friendly_id}, the class
+ # In addition to adding {FriendlyId::Base#friendly_id friendly_id}, the class
# instance variable +@friendly_id_config+ is added. This variable is an
# instance of an anonymous subclass of {FriendlyId::Configuration}. This
# allows subsequently loaded modules like {FriendlyId::Slugged} and
View
18 lib/friendly_id/base.rb
@@ -1,5 +1,5 @@
module FriendlyId
- # Class methods that will be added to ActiveRecord::Base.
+ # Class methods that will be added to model classes that extend {FriendlyId}.
module Base
# Configure FriendlyId's behavior in a model.
@@ -54,24 +54,35 @@ module Base
#
# @option options [Symbol] :use The name of an addon to use. By default,
# FriendlyId provides {FriendlyId::Slugged :slugged},
- # {FriendlyId::History :history}, {FriendlyId::Reserved}, and
+ # {FriendlyId::History :history}, {FriendlyId::Reserved :reserved}, and
# {FriendlyId::Scoped :scoped}.
- # @options options [Array] :reserved_words Available when using +:reserved+,
+ #
+ # @option options [Array] :reserved_words Available when using +:reserved+,
# which is loaded by default. Sets an array of words banned for use as
# the basis of a friendly_id. By default this includes "edit" and "new".
+ #
# @option options [Symbol] :scope Available when using +:scoped+.
# Sets the relation or column used to scope generated friendly ids. This
# option has no default value.
+ #
# @option options [Symbol] :sequence_separator Available when using +:slugged+.
# Configures the sequence of characters used to separate a slug from a
# sequence. Defaults to +--+.
+ #
# @option options [Symbol] :slug_column Available when using +:slugged+.
# Configures the name of the column where FriendlyId will store the slug.
# Defaults to +:slug+.
+ #
# @option options [Symbol] :slug_sequencer_class Available when using +:slugged+.
# Sets the class used to generate unique slugs. You should not specify this
# unless you're doing some extensive hacking on FriendlyId. Defaults to
# {FriendlyId::SlugSequencer}.
+ #
+ # @yield Provides access to the model class's friendly_id_config, which
+ # allows an alternate configuration syntax, and conditional configuration
+ # logic.
+ #
+ # @yieldparam config The model class's {FriendlyId::Configuration friendly_id_config}.
def friendly_id(base = nil, options = {}, &block)
yield @friendly_id_config if block_given?
@friendly_id_config.use options.delete :use
@@ -82,6 +93,7 @@ def friendly_id(base = nil, options = {}, &block)
include Model
end
+ # Returns the model class's {FriendlyId::Configuration friendly_id_config}.
def friendly_id_config
@friendly_id_config
end
View
1  lib/friendly_id/configuration.rb
@@ -27,6 +27,7 @@ class Configuration
# end
attr_accessor :base
+ # The default configuration options.
attr_reader :defaults
# The model class that this configuration belongs to.
View
8 lib/friendly_id/finder_methods.rb
@@ -4,6 +4,14 @@ module FinderMethods
protected
+ # FriendlyId overrides this method to make it possible to use friendly id's
+ # identically to numeric ids in finders.
+ #
+ # @example
+ # person = Person.find(123)
+ # person = Person.find("joe")
+ #
+ # @see FriendlyId::ObjectUtils
def find_one(id)
return super if !@klass.respond_to?(:friendly_id) || id.unfriendly_id?
where(@klass.friendly_id_config.query_field => id).first or super
View
22 lib/friendly_id/object_utils.rb
@@ -1,7 +1,11 @@
module FriendlyId
- # Utility methods that are in Object because it's impossible to predict what
- # kinds of objects get passed into FinderMethods#find_one and
- # Model#normalize_friendly_id.
+ # Utility methods for determining whether any object is a friendly id.
+ #
+ # Monkey-patching Object is a somewhat extreme measure not to be taken lightly
+ # by libraries, but in this case I decided to do it because to me, it feels
+ # cleaner than adding a module method to {FriendlyId}. I've given the methods
+ # names that unambigously refer to the library of their origin, which should
+ # be sufficient to avoid conflicts with other libraries.
module ObjectUtils
# True is the id is definitely friendly, false if definitely unfriendly,
@@ -9,6 +13,14 @@ module ObjectUtils
#
# An object is considired "definitely unfriendly" if its class is or
# inherits from Numeric, Symbol or ActiveRecord::Base.
+ #
+ # An object is considered "definitely friendly" if it responds to +to_i+,
+ # and its value when cast to an integer and then back to a string is
+ # different from its value when merely cast to a string:
+ #
+ # 123.friendly_id? #=> false
+ # "123".friendly_id? #=> nil
+ # "abc123".friendly_id? #=> true
def friendly_id?
if [Numeric, Symbol, ActiveRecord::Base].detect {|klass| self.class < klass}
false
@@ -25,6 +37,4 @@ def unfriendly_id?
end
end
-class Object
- include FriendlyId::ObjectUtils
-end
+Object.send :include, FriendlyId::ObjectUtils
View
23 lib/friendly_id/reserved.rb
@@ -1,8 +1,22 @@
module FriendlyId
- # This module adds the ability to exlude a list of words from use as
- # FriendlyId slugs.
+=begin
+This module adds the ability to exlude a list of words from use as
+FriendlyId slugs.
+
+By default, FriendlyId reserves the words "new" and "edit" when this module
+is included. You can configure this globally by using {FriendlyId.defaults FriendlyId.defaults}:
+
+ FriendlyId.defaults do |config|
+ config.use :reserved
+ # Reserve words for English and Spanish URLs
+ config.reserved_words = %w(new edit nueva nuevo editar)
+ end
+=end
module Reserved
+
+ # When included, this module adds configuration options to the model class's
+ # friendly_id_config.
def self.included(model_class)
model_class.class_eval do
friendly_id_config.class.send :include, Reserved::Configuration
@@ -10,15 +24,20 @@ def self.included(model_class)
end
end
+ # This module adds the +:reserved_words+ configuration option to
+ # {FriendlyId::Configuration FriendlyId::Configuration}.
module Configuration
attr_writer :reserved_words
+ # Overrides {FriendlyId::Configuration#base} to add a validation to the
+ # model class.
def base=(base)
super
reserved_words = model_class.friendly_id_config.reserved_words
model_class.validates_exclusion_of base, :in => reserved_words
end
+ # An array of words forbidden as slugs.
def reserved_words
@reserved_words ||= @defaults[:reserved_words]
end
View
9 lib/friendly_id/scoped.rb
@@ -101,10 +101,11 @@ module Configuration
# Gets the scope column.
#
- # Checks to see if the +:scope+ option passed to {#friendly_id}
- # refers to a relation, and if so, returns the realtion's foreign key.
- # Otherwise it assumes the option value was the name of column and returns
- # it cast to a String.
+ # Checks to see if the +:scope+ option passed to
+ # {FriendlyId::Base#friendly_id} refers to a relation, and if so, returns
+ # the realtion's foreign key. Otherwise it assumes the option value was
+ # the name of column and returns it cast to a String.
+ #
# @return String The scope column
def scope_column
(model_class.reflections[@scope].try(:association_foreign_key) || @scope).to_s
View
3  lib/friendly_id/slug.rb
@@ -1,3 +1,6 @@
+# A FriendlyId slug stored in an external table.
+#
+# @see FriendlyId::History
class FriendlyIdSlug < ActiveRecord::Base
belongs_to :sluggable, :polymorphic => true
end
View
107 lib/friendly_id/slugged.rb
@@ -5,10 +5,10 @@ module FriendlyId
=begin
This module adds in-table slugs to a model.
-Slugs are strings that have been processed to remove or replace characters that
-a developer considers inconvenient for use in URLs. For example, blog
-applications typically use a post title to provide the basis of a search engine
-friendly URL:
+Slugs are unique id strings that have been processed to remove or replace
+characters that a developer considers inconvenient for use in URLs. For example,
+blog applications typically use a post title to provide the basis of a search
+engine friendly URL:
"Gone With The Wind" -> "gone-with-the-wind"
@@ -17,7 +17,7 @@ module FriendlyId
though you may change this using the
{FriendlyId::Slugged::Configuration#slug_column slug_column} configuration
option. You should add an index to this field. You may also wish to constrain it
-to NOT NULL, but this is optional.
+to NOT NULL, but this depends on your app's behavior and requirements.
=== Example Setup
@@ -49,32 +49,51 @@ def self.down
By default, FriendlyId uses Active Support's
paramaterize[http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize]
-method to create slugs. This method will take care of intelligently replacing
-spaces with dashes, and replacing characters from Unicode Latin characters with
-ASCII approximations:
+method to create slugs. This method will intelligently replace spaces with
+dashes, and Unicode Latin characters with ASCII approximations:
movie = Movie.create! :title => "Der Preis fürs Überleben"
movie.slug #=> "der-preis-furs-uberleben"
==== Slug Uniqueness
-WRITE ME
+When you try to insert a record that would generate a duplicate friendly id,
+FriendlyId will append a sequence to the generated slug to ensure uniqueness:
+
+ car = Car.create :title => "Peugot 206"
+ car2 = Car.create :title => "Peugot 206"
+
+ car.friendly_id #=> "peugot-206"
+ car2.friendly_id #=> "peugot-206--2"
==== Changing the Slug Sequence Separator
-WRITE ME
+You can do this with the {Slugged::Configuration#sequence_separator
+sequence_separator} configuration option.
==== Column or Method?
-WRITE ME
+FriendlyId always uses a method as the basis of the slug text - not a column. It
+first glance, this may sound confusing, but remember that Active Record provides
+methods for each column in a model's associated table, and that's what
+FriendlyId uses.
-==== Providing Your Own Slug Processing Method
+Here's an example of a class that uses a custom method to generate the slug:
+
+ class Person < ActiveRecord::Base
+ friendly_id :name_and_location
+ def name_and_location
+ "#{name} from #{location}"
+ end
+ end
-WRITE ME
+ bob = Person.create! :name => "Bob Smith", :location => "New York City"
+ bob.friendly_id #=> "bob-smith-from-new-york-city"
-==== Babosa
+==== Providing Your Own Slug Processing Method
-WRITE ME
+You can override {Slugged#normalize_friendly_id} in your model for total
+control over the slug format.
==== Locale-specific Transliterations
@@ -99,6 +118,8 @@ def self.down
=end
module Slugged
+ # Sets up behavior and configuration options for FriendlyId's slugging
+ # feature.
def self.included(model_class)
model_class.instance_eval do
friendly_id_config.class.send :include, Configuration
@@ -109,6 +130,41 @@ def self.included(model_class)
end
end
+ # Process the given value to make it suitable for use as a slug.
+ #
+ # This method is not intended to be invoked directly; FriendlyId uses it
+ # internaly to process strings into slugs.
+ #
+ # However, if FriendlyId's default slug generation doesn't suite your needs,
+ # you can override this method in your model class to control exactly how
+ # slugs are generated.
+ #
+ # === Example
+ #
+ # class Person < ActiveRecord::Base
+ # friendly_id :name_and_location
+ #
+ # def name_and_location
+ # "#{name} from #{location}"
+ # end
+ #
+ # # Use default slug, but uupper case and with underscores
+ # def normalize_friendly_id(string)
+ # super.upcase.gsub("-", "_")
+ # end
+ # end
+ #
+ # bob = Person.create! :name => "Bob Smith", :location => "New York City"
+ # bob.friendly_id #=> "BOB_SMITH_FROM_NEW_YORK_CITY"
+ #
+ # === More Resources
+ #
+ # You might want to look into Babosa[https://github.com/norman/babosa],
+ # which is the slugging library used by FriendlyId prior to version 4, which
+ # offers some specialized functionality missing from Active Support.
+ #
+ # @param [#to_s] value The value used as the basis of the slug.
+ # @return The candidate slug text, without a sequence.
def normalize_friendly_id(value)
value.to_s.parameterize
end
@@ -117,20 +173,37 @@ def slug_sequencer
friendly_id_config.slug_sequencer_class.new(self)
end
- private
-
def set_slug
send "#{friendly_id_config.slug_column}=", slug_sequencer.generate
end
+ private :set_slug
+ # This module adds the +:slug_column+, and +:sequence_separator+, and
+ # +:slug_sequencer_class+ configuration options to
+ # {FriendlyId::Configuration FriendlyId::Configuration}.
module Configuration
attr_writer :slug_column, :sequence_separator
attr_accessor :slug_sequencer_class
+ # Makes FriendlyId use the slug column for querying.
+ # @return String The slug column.
def query_field
slug_column
end
+ # The string used to separate a slug base from a numeric sequence.
+ #
+ # By default, +--+ is used to separate the slug from the sequence.
+ # FriendlyId uses two dashes to distinguish sequences from slugs with
+ # numbers in their name.
+ #
+ # You can change the default separator by setting the
+ # {FriendlyId::Slugged::Configuration#sequence_separator
+ # sequence_separator} configuration option.
+ #
+ # For obvious reasons, you should avoid setting it to "+-+" unless you're
+ # sure you will never want to have a friendly id with a number in it.
+ # @return String The sequence separator string. Defaults to "+--+".
def sequence_separator
@sequence_separator or defaults[:sequence_separator]
end
Please sign in to comment.
Something went wrong with that request. Please try again.