friendly_id4 4.0.0.beta6 → 4.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +47 -68
- data/Rakefile +13 -108
- data/lib/friendly_id.rb +97 -117
- data/lib/friendly_id/scoped.rb +17 -116
- data/lib/friendly_id/slugged.rb +89 -183
- data/lib/friendly_id/test.rb +23 -0
- data/lib/friendly_id/test/generic.rb +84 -0
- data/lib/friendly_id/version.rb +9 -0
- data/test/core_test.rb +54 -16
- data/test/scoped_test.rb +39 -35
- data/test/slugged_test.rb +45 -64
- data/test/test_helper.rb +23 -0
- metadata +61 -125
- data/.gemtest +0 -0
- data/.gitignore +0 -11
- data/.yardopts +0 -4
- data/WhatsNew.md +0 -142
- data/bench.rb +0 -63
- data/friendly_id.gemspec +0 -31
- data/lib/friendly_id/base.rb +0 -134
- data/lib/friendly_id/configuration.rb +0 -78
- data/lib/friendly_id/finder_methods.rb +0 -20
- data/lib/friendly_id/history.rb +0 -64
- data/lib/friendly_id/migration.rb +0 -18
- data/lib/friendly_id/model.rb +0 -22
- data/lib/friendly_id/object_utils.rb +0 -40
- data/lib/friendly_id/reserved.rb +0 -46
- data/lib/friendly_id/slug.rb +0 -6
- data/lib/friendly_id/slug_sequencer.rb +0 -82
- data/lib/generators/friendly_id_generator.rb +0 -24
- data/test/base_test.rb +0 -54
- data/test/config/mysql.yml +0 -5
- data/test/config/mysql2.yml +0 -5
- data/test/config/postgres.yml +0 -6
- data/test/config/sqlite3.yml +0 -3
- data/test/configuration_test.rb +0 -27
- data/test/helper.rb +0 -90
- data/test/history_test.rb +0 -55
- data/test/object_utils_test.rb +0 -26
- data/test/reserved_test.rb +0 -26
- data/test/schema.rb +0 -56
- data/test/shared.rb +0 -118
- data/test/sti_test.rb +0 -48
data/friendly_id.gemspec
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
|
4
|
-
require "friendly_id"
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = "friendly_id4"
|
8
|
-
s.version = FriendlyId::VERSION
|
9
|
-
s.authors = ["Norman Clarke"]
|
10
|
-
s.email = ["norman@njclarke.com"]
|
11
|
-
s.homepage = "http://norman.github.com/friendly_id"
|
12
|
-
s.summary = "A comprehensive slugging and pretty-URL plugin."
|
13
|
-
s.rubyforge_project = "friendly_id"
|
14
|
-
s.files = `git ls-files`.split("\n")
|
15
|
-
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
16
|
-
s.require_paths = ["lib"]
|
17
|
-
|
18
|
-
s.add_development_dependency "activerecord", "~> 3.0"
|
19
|
-
s.add_development_dependency "sqlite3", "~> 1.3"
|
20
|
-
s.add_development_dependency "cutest", "~> 1.1.2"
|
21
|
-
s.add_development_dependency "ffaker"
|
22
|
-
s.add_development_dependency "maruku"
|
23
|
-
s.add_development_dependency "yard"
|
24
|
-
s.add_development_dependency "mocha"
|
25
|
-
|
26
|
-
s.description = <<-EOM
|
27
|
-
FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins
|
28
|
-
for Ruby on Rails. It allows you to create pretty URL's and work with
|
29
|
-
human-friendly strings as if they were numeric ids for ActiveRecord models.
|
30
|
-
EOM
|
31
|
-
end
|
data/lib/friendly_id/base.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
module FriendlyId
|
2
|
-
# Class methods that will be added to model classes that extend {FriendlyId}.
|
3
|
-
module Base
|
4
|
-
|
5
|
-
# Configure FriendlyId's behavior in a model.
|
6
|
-
#
|
7
|
-
# class Post < ActiveRecord::Base
|
8
|
-
# extend FriendlyId
|
9
|
-
# friendly_id :title, :use => :slugged
|
10
|
-
# end
|
11
|
-
#
|
12
|
-
# When given the optional block, this method will yield the class's instance
|
13
|
-
# of {FriendlyId::Configuration} to the block before evaluating other
|
14
|
-
# arguments, so configuration values set in the block may be overwritten by
|
15
|
-
# the arguments. This order was chosen to allow passing the same proc to
|
16
|
-
# multiple models, while being able to override the values it sets. Here is
|
17
|
-
# a contrived example:
|
18
|
-
#
|
19
|
-
# $friendly_id_config_proc = Proc.new do |config|
|
20
|
-
# config.base = :name
|
21
|
-
# config.use :slugged
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# class Foo < ActiveRecord::Base
|
25
|
-
# extend FriendlyId
|
26
|
-
# friendly_id &$friendly_id_config_proc
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# class Bar < ActiveRecord::Base
|
30
|
-
# extend FriendlyId
|
31
|
-
# friendly_id :title, &$friendly_id_config_proc
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# However, it's usually better to use {FriendlyId.defaults} for this:
|
35
|
-
#
|
36
|
-
# FriendlyId.defaults do |config|
|
37
|
-
# config.base = :name
|
38
|
-
# config.use :slugged
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# class Foo < ActiveRecord::Base
|
42
|
-
# extend FriendlyId
|
43
|
-
# end
|
44
|
-
#
|
45
|
-
# class Bar < ActiveRecord::Base
|
46
|
-
# extend FriendlyId
|
47
|
-
# friendly_id :title
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# In general you should use the block syntax either because of your personal
|
51
|
-
# aesthetic preference, or because you need to share some functionality
|
52
|
-
# between multiple models that can't be well encapsulated by
|
53
|
-
# {FriendlyId.defaults}.
|
54
|
-
#
|
55
|
-
# === Order Method Calls in a Block vs Ordering Options
|
56
|
-
#
|
57
|
-
# When calling this method without a block, you may set the hash options in
|
58
|
-
# any order.
|
59
|
-
#
|
60
|
-
# However, when using block-style invocation, be sure to call
|
61
|
-
# FriendlyId::Configuration's {FriendlyId::Configuration#use use} method
|
62
|
-
# *prior* to the associated configuration options, because it will include
|
63
|
-
# modules into your class, and these modules in turn may add required
|
64
|
-
# configuration options to the +@friendly_id_configuraton+'s class:
|
65
|
-
#
|
66
|
-
# class Person < ActiveRecord::Base
|
67
|
-
# friendly_id do |config|
|
68
|
-
# # This will work
|
69
|
-
# config.use :slugged
|
70
|
-
# config.sequence_separator = ":"
|
71
|
-
# end
|
72
|
-
# end
|
73
|
-
#
|
74
|
-
# class Person < ActiveRecord::Base
|
75
|
-
# friendly_id do |config|
|
76
|
-
# # This will fail
|
77
|
-
# config.sequence_separator = ":"
|
78
|
-
# config.use :slugged
|
79
|
-
# end
|
80
|
-
# end
|
81
|
-
#
|
82
|
-
# @option options [Symbol] :use The name of an addon to use. By default,
|
83
|
-
# FriendlyId provides {FriendlyId::Slugged :slugged},
|
84
|
-
# {FriendlyId::History :history}, {FriendlyId::Reserved :reserved}, and
|
85
|
-
# {FriendlyId::Scoped :scoped}.
|
86
|
-
#
|
87
|
-
# @option options [Array] :reserved_words Available when using +:reserved+,
|
88
|
-
# which is loaded by default. Sets an array of words banned for use as
|
89
|
-
# the basis of a friendly_id. By default this includes "edit" and "new".
|
90
|
-
#
|
91
|
-
# @option options [Symbol] :scope Available when using +:scoped+.
|
92
|
-
# Sets the relation or column used to scope generated friendly ids. This
|
93
|
-
# option has no default value.
|
94
|
-
#
|
95
|
-
# @option options [Symbol] :sequence_separator Available when using +:slugged+.
|
96
|
-
# Configures the sequence of characters used to separate a slug from a
|
97
|
-
# sequence. Defaults to +--+.
|
98
|
-
#
|
99
|
-
# @option options [Symbol] :slug_column Available when using +:slugged+.
|
100
|
-
# Configures the name of the column where FriendlyId will store the slug.
|
101
|
-
# Defaults to +:slug+.
|
102
|
-
#
|
103
|
-
# @option options [Symbol] :slug_sequencer_class Available when using +:slugged+.
|
104
|
-
# Sets the class used to generate unique slugs. You should not specify this
|
105
|
-
# unless you're doing some extensive hacking on FriendlyId. Defaults to
|
106
|
-
# {FriendlyId::SlugSequencer}.
|
107
|
-
#
|
108
|
-
# @yield Provides access to the model class's friendly_id_config, which
|
109
|
-
# allows an alternate configuration syntax, and conditional configuration
|
110
|
-
# logic.
|
111
|
-
#
|
112
|
-
# @yieldparam config The model class's {FriendlyId::Configuration friendly_id_config}.
|
113
|
-
def friendly_id(base = nil, options = {}, &block)
|
114
|
-
yield @friendly_id_config if block_given?
|
115
|
-
@friendly_id_config.use options.delete :use
|
116
|
-
@friendly_id_config.send :set, base ? options.merge(:base => base) : options
|
117
|
-
before_save do |record|
|
118
|
-
record.instance_eval {@current_friendly_id = friendly_id}
|
119
|
-
end
|
120
|
-
include Model
|
121
|
-
end
|
122
|
-
|
123
|
-
# Returns the model class's {FriendlyId::Configuration friendly_id_config}.
|
124
|
-
# @note In the case of Single Table Inheritance (STI), this method will
|
125
|
-
# duplicate the parent class's FriendlyId::Configuration instance on first
|
126
|
-
# access. If you're concerned about thread safety, then be sure to invoke
|
127
|
-
# {#friendly_id} in your class for each model.
|
128
|
-
def friendly_id_config
|
129
|
-
@friendly_id_config or begin
|
130
|
-
@friendly_id_config = base_class.friendly_id_config.dup
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
module FriendlyId
|
2
|
-
# The configuration paramters passed to +friendly_id+ will be stored in
|
3
|
-
# this object.
|
4
|
-
class Configuration
|
5
|
-
|
6
|
-
# The base column or method used by FriendlyId as the basis of a friendly id
|
7
|
-
# or slug.
|
8
|
-
#
|
9
|
-
# For models that don't use FriendlyId::Slugged, the base is the column that
|
10
|
-
# is used as the FriendlyId directly. For models using FriendlyId::Slugged,
|
11
|
-
# the base is a column or method whose value is used as the basis of the
|
12
|
-
# slug.
|
13
|
-
#
|
14
|
-
# For example, if you have a model representing blog posts and that uses
|
15
|
-
# slugs, you likely will want to use the "title" attribute as the base, and
|
16
|
-
# FriendlyId will take care of transforming the human-readable title into
|
17
|
-
# something suitable for use in a URL.
|
18
|
-
#
|
19
|
-
# @param [Symbol] A symbol referencing a column or method in the model. This
|
20
|
-
# value is usually set by passing it as the first argument to
|
21
|
-
# {FriendlyId::Base#friendly_id friendly_id}:
|
22
|
-
#
|
23
|
-
# @example
|
24
|
-
# class Book < ActiveRecord::Base
|
25
|
-
# extend FriendlyId
|
26
|
-
# friendly_id :name
|
27
|
-
# end
|
28
|
-
attr_accessor :base
|
29
|
-
|
30
|
-
# The default configuration options.
|
31
|
-
attr_reader :defaults
|
32
|
-
|
33
|
-
# The model class that this configuration belongs to.
|
34
|
-
# @return ActiveRecord::Base
|
35
|
-
attr_reader :model_class
|
36
|
-
|
37
|
-
def initialize(model_class, values = nil)
|
38
|
-
@model_class = model_class
|
39
|
-
@defaults = {}
|
40
|
-
set values
|
41
|
-
end
|
42
|
-
|
43
|
-
# Lets you specify the modules to use with FriendlyId.
|
44
|
-
#
|
45
|
-
# This method is invoked by {FriendlyId::Base#friendly_id friendly_id} when
|
46
|
-
# passing the +:use+ option, or when using {FriendlyId::Base#friendly_id
|
47
|
-
# friendly_id} with a block.
|
48
|
-
#
|
49
|
-
# @example
|
50
|
-
# class Book < ActiveRecord::Base
|
51
|
-
# extend FriendlyId
|
52
|
-
# friendly_id :name, :use => :slugged
|
53
|
-
# end
|
54
|
-
# @param [#to_s] *modules Arguments should be a symbols or strings that
|
55
|
-
# correspond with the name of a module inside the FriendlyId namespace. By
|
56
|
-
# default FriendlyId provides +:slugged+, +:history+ and +:scoped+.
|
57
|
-
def use(*modules)
|
58
|
-
modules.to_a.flatten.compact.map do |name|
|
59
|
-
model_class.send :include, FriendlyId.const_get(name.to_s.classify)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# The column that FriendlyId will use to find the record when querying by
|
64
|
-
# friendly id.
|
65
|
-
#
|
66
|
-
# This method is generally only used internally by FriendlyId.
|
67
|
-
# @return String
|
68
|
-
def query_field
|
69
|
-
base.to_s
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
def set(values)
|
75
|
-
values and values.each {|name, value| self.send "#{name}=", value}
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module FriendlyId
|
2
|
-
# These methods will override the finder methods in ActiveRecord::Relation.
|
3
|
-
module FinderMethods
|
4
|
-
|
5
|
-
protected
|
6
|
-
|
7
|
-
# FriendlyId overrides this method to make it possible to use friendly id's
|
8
|
-
# identically to numeric ids in finders.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# person = Person.find(123)
|
12
|
-
# person = Person.find("joe")
|
13
|
-
#
|
14
|
-
# @see FriendlyId::ObjectUtils
|
15
|
-
def find_one(id)
|
16
|
-
return super if !@klass.respond_to?(:friendly_id) || id.unfriendly_id?
|
17
|
-
where(@klass.friendly_id_config.query_field => id).first or super
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/friendly_id/history.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
require "friendly_id/slug"
|
2
|
-
|
3
|
-
module FriendlyId
|
4
|
-
|
5
|
-
=begin
|
6
|
-
FriendlyId can maintain a history of your record's older slugs, so if your
|
7
|
-
record's friendly_id changes, your URL's won't break.
|
8
|
-
|
9
|
-
class Post < ActiveRecord::Base
|
10
|
-
extend FriendlyId
|
11
|
-
friendly_id :title, :use => :history
|
12
|
-
end
|
13
|
-
|
14
|
-
class PostsController < ApplicationController
|
15
|
-
|
16
|
-
before_filter :find_post
|
17
|
-
|
18
|
-
...
|
19
|
-
def find_post
|
20
|
-
return unless params[:id]
|
21
|
-
@post = begin
|
22
|
-
Post.find params[:id]
|
23
|
-
rescue ActiveRecord::RecordNotFound
|
24
|
-
Post.find_by_friendly_id params[:id]
|
25
|
-
end
|
26
|
-
# If an old id or a numeric id was used to find the record, then
|
27
|
-
# the request path will not match the post_path, and we should do
|
28
|
-
# a 301 redirect that uses the current friendly_id
|
29
|
-
if request.path != post_path(@post)
|
30
|
-
return redirect_to @post, :status => :moved_permanently
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
=end
|
35
|
-
module History
|
36
|
-
|
37
|
-
# Configures the model instance to use the History add-on.
|
38
|
-
def self.included(klass)
|
39
|
-
klass.instance_eval do
|
40
|
-
raise "FriendlyId::History is incompatibe with FriendlyId::Scoped" if self < Scoped
|
41
|
-
include Slugged unless self < Slugged
|
42
|
-
has_many :friendly_id_slugs, :as => :sluggable, :dependent => :destroy
|
43
|
-
before_save :build_friendly_id_slug, :if => lambda {|r| r.slug_sequencer.slug_changed?}
|
44
|
-
scope :with_friendly_id, lambda {|id| includes(:friendly_id_slugs).where("friendly_id_slugs.slug = ?", id)}
|
45
|
-
extend Finder
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def build_friendly_id_slug
|
52
|
-
self.friendly_id_slugs.build :slug => friendly_id
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Adds a finder that explictly uses slugs from the slug table.
|
57
|
-
module Finder
|
58
|
-
|
59
|
-
# Search for a record in the slugs table using the specified slug.
|
60
|
-
def find_by_friendly_id(*args)
|
61
|
-
with_friendly_id(args.shift).first(*args)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class CreateFriendlyIdSlugs < ActiveRecord::Migration
|
2
|
-
|
3
|
-
def self.up
|
4
|
-
create_table :friendly_id_slugs do |t|
|
5
|
-
t.string :slug, :null => false
|
6
|
-
t.integer :sluggable_id, :null => false
|
7
|
-
t.string :sluggable_type, :limit => 40
|
8
|
-
t.datetime :created_at
|
9
|
-
end
|
10
|
-
add_index :friendly_id_slugs, :sluggable_id
|
11
|
-
add_index :friendly_id_slugs, [:slug, :sluggable_type], :unique => true
|
12
|
-
add_index :friendly_id_slugs, :sluggable_type
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.down
|
16
|
-
drop_table :friendly_id_slugs
|
17
|
-
end
|
18
|
-
end
|
data/lib/friendly_id/model.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module FriendlyId
|
2
|
-
# Instance methods that will be added to all classes using FriendlyId.
|
3
|
-
module Model
|
4
|
-
|
5
|
-
attr_reader :current_friendly_id
|
6
|
-
|
7
|
-
# Convenience method for accessing the class method of the same name.
|
8
|
-
def friendly_id_config
|
9
|
-
self.class.friendly_id_config
|
10
|
-
end
|
11
|
-
|
12
|
-
# Get the instance's friendly_id.
|
13
|
-
def friendly_id
|
14
|
-
send friendly_id_config.query_field
|
15
|
-
end
|
16
|
-
|
17
|
-
# Either the friendly_id, or the numeric id cast to a string.
|
18
|
-
def to_param
|
19
|
-
(friendly_id.present? ? friendly_id : id).to_s
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module FriendlyId
|
2
|
-
# Utility methods for determining whether any object is a friendly id.
|
3
|
-
#
|
4
|
-
# Monkey-patching Object is a somewhat extreme measure not to be taken lightly
|
5
|
-
# by libraries, but in this case I decided to do it because to me, it feels
|
6
|
-
# cleaner than adding a module method to {FriendlyId}. I've given the methods
|
7
|
-
# names that unambigously refer to the library of their origin, which should
|
8
|
-
# be sufficient to avoid conflicts with other libraries.
|
9
|
-
module ObjectUtils
|
10
|
-
|
11
|
-
# True is the id is definitely friendly, false if definitely unfriendly,
|
12
|
-
# else nil.
|
13
|
-
#
|
14
|
-
# An object is considired "definitely unfriendly" if its class is or
|
15
|
-
# inherits from Numeric, Symbol or ActiveRecord::Base.
|
16
|
-
#
|
17
|
-
# An object is considered "definitely friendly" if it responds to +to_i+,
|
18
|
-
# and its value when cast to an integer and then back to a string is
|
19
|
-
# different from its value when merely cast to a string:
|
20
|
-
#
|
21
|
-
# 123.friendly_id? #=> false
|
22
|
-
# "123".friendly_id? #=> nil
|
23
|
-
# "abc123".friendly_id? #=> true
|
24
|
-
def friendly_id?
|
25
|
-
if [Numeric, Symbol, ActiveRecord::Base].detect {|klass| self.class < klass}
|
26
|
-
false
|
27
|
-
elsif respond_to?(:to_i) && to_i.to_s != to_s
|
28
|
-
true
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# True if the id is definitely unfriendly, false if definitely friendly,
|
33
|
-
# else nil.
|
34
|
-
def unfriendly_id?
|
35
|
-
val = friendly_id? ; !val unless val.nil?
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
Object.send :include, FriendlyId::ObjectUtils
|
data/lib/friendly_id/reserved.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module FriendlyId
|
2
|
-
|
3
|
-
=begin
|
4
|
-
This module adds the ability to exlude a list of words from use as
|
5
|
-
FriendlyId slugs.
|
6
|
-
|
7
|
-
By default, FriendlyId reserves the words "new" and "edit" when this module
|
8
|
-
is included. You can configure this globally by using {FriendlyId.defaults FriendlyId.defaults}:
|
9
|
-
|
10
|
-
FriendlyId.defaults do |config|
|
11
|
-
config.use :reserved
|
12
|
-
# Reserve words for English and Spanish URLs
|
13
|
-
config.reserved_words = %w(new edit nueva nuevo editar)
|
14
|
-
end
|
15
|
-
=end
|
16
|
-
module Reserved
|
17
|
-
|
18
|
-
# When included, this module adds configuration options to the model class's
|
19
|
-
# friendly_id_config.
|
20
|
-
def self.included(model_class)
|
21
|
-
model_class.class_eval do
|
22
|
-
friendly_id_config.class.send :include, Reserved::Configuration
|
23
|
-
friendly_id_config.defaults[:reserved_words] ||= ["new", "edit"]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# This module adds the +:reserved_words+ configuration option to
|
28
|
-
# {FriendlyId::Configuration FriendlyId::Configuration}.
|
29
|
-
module Configuration
|
30
|
-
attr_writer :reserved_words
|
31
|
-
|
32
|
-
# Overrides {FriendlyId::Configuration#base} to add a validation to the
|
33
|
-
# model class.
|
34
|
-
def base=(base)
|
35
|
-
super
|
36
|
-
reserved_words = model_class.friendly_id_config.reserved_words
|
37
|
-
model_class.validates_exclusion_of base, :in => reserved_words
|
38
|
-
end
|
39
|
-
|
40
|
-
# An array of words forbidden as slugs.
|
41
|
-
def reserved_words
|
42
|
-
@reserved_words ||= @defaults[:reserved_words]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|