friendly_id 5.0.0.beta3 → 5.0.0.beta4
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.
- checksums.yaml +4 -4
- data/Changelog.md +6 -0
- data/README.md +80 -56
- data/lib/friendly_id.rb +4 -9
- data/lib/friendly_id/base.rb +50 -50
- data/lib/friendly_id/configuration.rb +35 -29
- data/lib/friendly_id/initializer.rb +84 -0
- data/lib/friendly_id/reserved.rb +12 -29
- data/lib/friendly_id/slugged.rb +6 -1
- data/lib/friendly_id/version.rb +1 -1
- data/lib/generators/friendly_id_generator.rb +8 -0
- data/test/configuration_test.rb +16 -0
- data/test/generator_test.rb +28 -0
- data/test/reserved_test.rb +3 -3
- data/test/slugged_test.rb +9 -8
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04766b0ed96f1b271571b983cf3b73cf9385406c
|
4
|
+
data.tar.gz: 5881c90dc07cf35780402d04211cc93ebd597d01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06b4a78391d3a6f9ca7a42e4769087e4dbf70a559e29313147b48b655dbc59ffddfbaf3f91e78854d64c8b1cedf1bf2e088280c9747fcb9fc45318ec7243d925
|
7
|
+
data.tar.gz: 2e66f50e25d14cf807e2f2719c49e13e2936656ac50a6842f1225357089e0561b2ec39effad76571558999d04d905715f365649cd1119b7a2a8765dd81084c79
|
data/Changelog.md
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
We would like to think our many {file:Contributors contributors} for
|
4
4
|
suggestions, ideas and improvements to FriendlyId.
|
5
5
|
|
6
|
+
## 5.0.0.beta4 (2013-08-21)
|
7
|
+
|
8
|
+
* Add an initializer to the generator; move the default reserved words there.
|
9
|
+
* Allow assignment from {FriendlyId::Configuration#base}.
|
10
|
+
* Fix bug whereby records could not reuse their own slugs.
|
11
|
+
|
6
12
|
## 5.0.0.beta3 (2013-08-20)
|
7
13
|
|
8
14
|
* Update gemspec to ensure FriendlyId 5.0 is only used with AR 4.0.x.
|
data/README.md
CHANGED
@@ -3,12 +3,14 @@
|
|
3
3
|
**VERSION NOTE**
|
4
4
|
|
5
5
|
**Rails 4**:
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
The master branch of this repository contains FriendlyId 5, which is compatible
|
8
|
+
with Rails 4. This version is in beta and will be released soon.
|
8
9
|
|
9
10
|
**Rails 3**:
|
10
|
-
|
11
|
-
|
11
|
+
|
12
|
+
If you wish to use this gem with Rails 3.1 or 3.2 you must use FriendlyId 4,
|
13
|
+
which is the current stable release. Please see the [4.0-stable
|
12
14
|
branch](https://github.com/norman/friendly_id/tree/4.0-stable).
|
13
15
|
|
14
16
|
# FriendlyId
|
@@ -16,10 +18,10 @@ branch](https://github.com/norman/friendly_id/tree/4.0-stable).
|
|
16
18
|
<em>For the most complete, user-friendly documentation, see the [FriendlyId Guide](http://rubydoc.info/github/norman/friendly_id/master/file/Guide.md).</em>
|
17
19
|
|
18
20
|
FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
|
19
|
-
|
20
|
-
strings as if they were numeric ids
|
21
|
+
Active Record. It lets you create pretty URLs and work with human-friendly
|
22
|
+
strings as if they were numeric ids.
|
21
23
|
|
22
|
-
|
24
|
+
With FriendlyId, it's easy to make your application use URLs like:
|
23
25
|
|
24
26
|
http://example.com/states/washington
|
25
27
|
|
@@ -33,49 +35,41 @@ instead of:
|
|
33
35
|
FriendlyId offers many advanced features, including: slug history and
|
34
36
|
versioning, i18n, scoped slugs, reserved words, and custom slug generators.
|
35
37
|
|
36
|
-
|
37
|
-
For Rails 3.x, please use FriendlyId 4.x.
|
38
|
-
|
39
|
-
|
40
|
-
## Version 5.x
|
38
|
+
### What Changed in Version 5.0
|
41
39
|
|
42
40
|
As of version 5.0, FriendlyId uses semantic versioning. Therefore, as you might
|
43
|
-
infer from the version number,
|
44
|
-
with 4.x.
|
41
|
+
infer from the version number, 5.0 introduces changes incompatible with 4.0.
|
45
42
|
|
46
|
-
|
43
|
+
The most important changes are:
|
47
44
|
|
48
|
-
*
|
49
|
-
you must do `Model.friendly.find` rather than `Model.find`. You can however
|
45
|
+
* Finders are no longer overridden by default. If you want to do friendly finds,
|
46
|
+
you must do `Model.friendly.find` rather than `Model.find`. You can however
|
50
47
|
restore FriendlyId 4-style finders by using the `:finders` addon:
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
#
|
55
|
-
friendly_id :foo, use: [:slugged, :finders] # you can now do MyClass.find('bar')
|
56
|
-
```
|
49
|
+
friendly_id :foo, use: :slugged # you must do MyClass.friendly.find('bar')
|
50
|
+
# or...
|
51
|
+
friendly_id :foo, use: [:slugged, :finders] # you can now do MyClass.find('bar')
|
57
52
|
|
58
|
-
* Version 5.0 offers a new "candidates" functionality which makes it easy to
|
59
|
-
set up a list of alternate slugs that can be used to uniquely distinguish
|
60
|
-
records, rather than appending a sequence. For example:
|
61
53
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
54
|
+
* A new "candidates" functionality which makes it easy to set up a list of
|
55
|
+
alternate slugs that can be used to uniquely distinguish records, rather than
|
56
|
+
appending a sequence. For example:
|
57
|
+
|
58
|
+
class Restaurant < ActiveRecord::Base
|
59
|
+
extend FriendlyId
|
60
|
+
friendly_id :slug_candidates, use: :slugged
|
61
|
+
|
62
|
+
# Try building a slug based on the following fields in
|
63
|
+
# increasing order of specificity.
|
64
|
+
def slug_candidates
|
65
|
+
[
|
66
|
+
:name,
|
67
|
+
[:name, :city],
|
68
|
+
[:name, :street, :city],
|
69
|
+
[:name, :street_number, :street, :city]
|
70
|
+
]
|
71
|
+
end
|
72
|
+
end
|
79
73
|
|
80
74
|
* Now that candidates have been added, FriendlyId no longer uses a numeric
|
81
75
|
sequence to differentiate conflicting slug, but rather a UUID (e.g. something
|
@@ -83,26 +77,56 @@ end
|
|
83
77
|
codebase simpler and more reliable when running concurrently, at the expense
|
84
78
|
of uglier ids being generated when there are conflicts.
|
85
79
|
|
86
|
-
* The default sequence separator
|
80
|
+
* The default sequence separator has been changed from two dashes to one dash.
|
87
81
|
|
88
82
|
* Slugs are no longer regenerated when a record is saved. If you want to regenerate
|
89
83
|
a slug, you must explicitly set the slug column to nil:
|
90
84
|
|
91
|
-
|
92
|
-
restaurant.
|
93
|
-
restaurant.
|
94
|
-
restaurant.
|
95
|
-
restaurant.
|
96
|
-
restaurant.
|
97
|
-
restaurant.
|
98
|
-
|
99
|
-
|
85
|
+
restaurant.friendly_id # joes-diner
|
86
|
+
restaurant.name = "The Plaza Diner"
|
87
|
+
restaurant.save!
|
88
|
+
restaurant.friendly_id # joes-diner
|
89
|
+
restaurant.slug = nil
|
90
|
+
restaurant.save!
|
91
|
+
restaurant.friendly_id # the-plaza-diner
|
92
|
+
|
93
|
+
You can restore some of the old behavior by overriding the
|
94
|
+
`should_generate_new_friendly_id` method.
|
95
|
+
|
96
|
+
* The `friendly_id` Rails generator now generates an initializer showing you
|
97
|
+
how to do some commmon global configuration.
|
98
|
+
|
99
|
+
* The `:reserved` module no longer includes any default reserved words.
|
100
|
+
Previously it blocked "edit" and "new" everywhere. The default word list has
|
101
|
+
been moved to `config/initializers/friendly_id.rb` and now includes many more
|
102
|
+
words.
|
103
|
+
|
104
|
+
* The `:history` and `:scoped` addons can now be used together.
|
105
|
+
|
106
|
+
* Since it now requires Rails 4, FriendlyId also now requires Ruby 1.9.3 or
|
107
|
+
higher.
|
108
|
+
|
109
|
+
#### Upgrading from FriendlyId 4.0
|
110
|
+
|
111
|
+
Run `rails generate friendly_id --skip-migration` and edit the initializer
|
112
|
+
generated in `config/initializers/friendly_id.rb`. This file contains notes
|
113
|
+
describing how to restore (or not) some of the defaults from FriendlyId 4.0.
|
114
|
+
|
115
|
+
If you want to use the `:history` and `:scoped` addons together, you must add a
|
116
|
+
`:scope` column to your friendly_id slugs table and replace the unique index on
|
117
|
+
`:slug` and `:sluggable_type` with a unique index on those two columns, plus
|
118
|
+
the new `:scope` column.
|
119
|
+
|
120
|
+
A migration like this should be sufficient:
|
100
121
|
|
101
|
-
|
122
|
+
add_column :friendly_id_slugs, :scope, :string
|
123
|
+
remove_index :friendly_id_slugs, [:slug, :sluggable_type]
|
124
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type]
|
125
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], unique: true
|
102
126
|
|
103
127
|
## Docs
|
104
128
|
|
105
|
-
The current docs can always be found
|
129
|
+
The most current docs from the master branch can always be found
|
106
130
|
[here](http://rubydoc.info/github/norman/friendly_id/master/frames).
|
107
131
|
|
108
132
|
The best place to start is with the
|
@@ -110,7 +134,7 @@ The best place to start is with the
|
|
110
134
|
which compiles the top-level RDocs into one outlined document.
|
111
135
|
|
112
136
|
You might also want to watch Ryan Bates's [Railscast on FriendlyId](http://railscasts.com/episodes/314-pretty-urls-with-friendlyid),
|
113
|
-
which is now somewhat outdated but still
|
137
|
+
which is now somewhat outdated but still relevant.
|
114
138
|
|
115
139
|
## Rails Quickstart
|
116
140
|
|
@@ -120,7 +144,7 @@ cd my_app
|
|
120
144
|
```
|
121
145
|
```ruby
|
122
146
|
# Gemfile
|
123
|
-
gem 'friendly_id', '5.0.0.
|
147
|
+
gem 'friendly_id', '5.0.0.beta4' # Note: You MUST use 5.0.0 or greater for Rails 4.0+
|
124
148
|
```
|
125
149
|
```shell
|
126
150
|
rails generate friendly_id
|
data/lib/friendly_id.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "thread"
|
3
2
|
require "friendly_id/base"
|
4
3
|
require "friendly_id/object_utils"
|
5
4
|
require "friendly_id/configuration"
|
@@ -43,8 +42,6 @@ with numeric ids:
|
|
43
42
|
=end
|
44
43
|
module FriendlyId
|
45
44
|
|
46
|
-
@mutex = Mutex.new
|
47
|
-
|
48
45
|
autoload :History, "friendly_id/history"
|
49
46
|
autoload :Slug, "friendly_id/slug"
|
50
47
|
autoload :SimpleI18n, "friendly_id/simple_i18n"
|
@@ -95,18 +92,16 @@ module FriendlyId
|
|
95
92
|
|
96
93
|
# Set global defaults for all models using FriendlyId.
|
97
94
|
#
|
98
|
-
# The default defaults are to use the
|
95
|
+
# The default defaults are to use the `:reserved` module and nothing else.
|
99
96
|
#
|
100
97
|
# @example
|
101
98
|
# FriendlyId.defaults do |config|
|
102
|
-
# config.base
|
99
|
+
# config.base :name
|
103
100
|
# config.use :slugged
|
104
101
|
# end
|
105
102
|
def self.defaults(&block)
|
106
|
-
@
|
107
|
-
|
108
|
-
@defaults ||= lambda {|config| config.use :reserved}
|
109
|
-
end
|
103
|
+
@defaults = block if block_given?
|
104
|
+
@defaults ||= ->(config) {config.use :reserved}
|
110
105
|
end
|
111
106
|
|
112
107
|
# Set the ActiveRecord table name prefix to friendly_id_
|
data/lib/friendly_id/base.rb
CHANGED
@@ -55,10 +55,10 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
55
55
|
|
56
56
|
# Configure FriendlyId's behavior in a model.
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
58
|
+
# class Post < ActiveRecord::Base
|
59
|
+
# extend FriendlyId
|
60
|
+
# friendly_id :title, :use => :slugged
|
61
|
+
# end
|
62
62
|
#
|
63
63
|
# When given the optional block, this method will yield the class's instance
|
64
64
|
# of {FriendlyId::Configuration} to the block before evaluating other
|
@@ -67,36 +67,36 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
67
67
|
# multiple models, while being able to override the values it sets. Here is
|
68
68
|
# a contrived example:
|
69
69
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
70
|
+
# $friendly_id_config_proc = Proc.new do |config|
|
71
|
+
# config.base = :name
|
72
|
+
# config.use :slugged
|
73
|
+
# end
|
74
74
|
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
75
|
+
# class Foo < ActiveRecord::Base
|
76
|
+
# extend FriendlyId
|
77
|
+
# friendly_id &$friendly_id_config_proc
|
78
|
+
# end
|
79
79
|
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
80
|
+
# class Bar < ActiveRecord::Base
|
81
|
+
# extend FriendlyId
|
82
|
+
# friendly_id :title, &$friendly_id_config_proc
|
83
|
+
# end
|
84
84
|
#
|
85
85
|
# However, it's usually better to use {FriendlyId.defaults} for this:
|
86
86
|
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
87
|
+
# FriendlyId.defaults do |config|
|
88
|
+
# config.base = :name
|
89
|
+
# config.use :slugged
|
90
|
+
# end
|
91
91
|
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
92
|
+
# class Foo < ActiveRecord::Base
|
93
|
+
# extend FriendlyId
|
94
|
+
# end
|
95
95
|
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
96
|
+
# class Bar < ActiveRecord::Base
|
97
|
+
# extend FriendlyId
|
98
|
+
# friendly_id :title
|
99
|
+
# end
|
100
100
|
#
|
101
101
|
# In general you should use the block syntax either because of your personal
|
102
102
|
# aesthetic preference, or because you need to share some functionality
|
@@ -114,21 +114,21 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
114
114
|
# modules into your class, and these modules in turn may add required
|
115
115
|
# configuration options to the `@friendly_id_configuraton`'s class:
|
116
116
|
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
117
|
+
# class Person < ActiveRecord::Base
|
118
|
+
# friendly_id do |config|
|
119
|
+
# # This will work
|
120
|
+
# config.use :slugged
|
121
|
+
# config.sequence_separator = ":"
|
122
|
+
# end
|
122
123
|
# end
|
123
|
-
# end
|
124
124
|
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
125
|
+
# class Person < ActiveRecord::Base
|
126
|
+
# friendly_id do |config|
|
127
|
+
# # This will fail
|
128
|
+
# config.sequence_separator = ":"
|
129
|
+
# config.use :slugged
|
130
|
+
# end
|
130
131
|
# end
|
131
|
-
# end
|
132
132
|
#
|
133
133
|
# ### Including Your Own Modules
|
134
134
|
#
|
@@ -136,21 +136,21 @@ often better and easier to use {FriendlyId::Slugged slugs}.
|
|
136
136
|
# can be a convenient place to set up behavior common to all classes using
|
137
137
|
# FriendlyId. You can include any module, or more conveniently, define one
|
138
138
|
# on-the-fly. For example, let's say you want to make
|
139
|
-
# Babosa
|
139
|
+
# [Babosa](http://github.com/norman/babosa) the default slugging library in
|
140
140
|
# place of Active Support, and transliterate all slugs from Russian Cyrillic
|
141
141
|
# to ASCII:
|
142
142
|
#
|
143
|
-
#
|
143
|
+
# require "babosa"
|
144
144
|
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
145
|
+
# FriendlyId.defaults do |config|
|
146
|
+
# config.base = :name
|
147
|
+
# config.use :slugged
|
148
|
+
# config.use Module.new {
|
149
|
+
# def normalize_friendly_id(text)
|
150
|
+
# text.to_slug.normalize! :transliterations => [:russian, :latin]
|
151
|
+
# end
|
152
|
+
# }
|
153
|
+
# end
|
154
154
|
#
|
155
155
|
#
|
156
156
|
# @option options [Symbol,Module] :use The addon or name of an addon to use.
|
@@ -1,31 +1,9 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
# The configuration paramters passed to
|
2
|
+
# The configuration paramters passed to {Base#friendly_id} will be stored in
|
3
3
|
# this object.
|
4
4
|
class Configuration
|
5
5
|
|
6
|
-
|
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
|
-
# 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
|
6
|
+
attr_writer :base
|
29
7
|
|
30
8
|
# The default configuration options.
|
31
9
|
attr_reader :defaults
|
@@ -44,10 +22,10 @@ module FriendlyId
|
|
44
22
|
set values
|
45
23
|
end
|
46
24
|
|
47
|
-
# Lets you specify the modules to use with FriendlyId.
|
25
|
+
# Lets you specify the addon modules to use with FriendlyId.
|
48
26
|
#
|
49
27
|
# This method is invoked by {FriendlyId::Base#friendly_id friendly_id} when
|
50
|
-
# passing the
|
28
|
+
# passing the `:use` option, or when using {FriendlyId::Base#friendly_id
|
51
29
|
# friendly_id} with a block.
|
52
30
|
#
|
53
31
|
# @example
|
@@ -55,10 +33,11 @@ module FriendlyId
|
|
55
33
|
# extend FriendlyId
|
56
34
|
# friendly_id :name, :use => :slugged
|
57
35
|
# end
|
36
|
+
#
|
58
37
|
# @param [#to_s,Module] modules Arguments should be Modules, or symbols or
|
59
|
-
# strings that correspond with the name of
|
60
|
-
#
|
61
|
-
#
|
38
|
+
# strings that correspond with the name of an addon to use with FriendlyId.
|
39
|
+
# By default FriendlyId provides `:slugged`, `:history`, `:simple_i18n`,
|
40
|
+
# and `:scoped`.
|
62
41
|
def use(*modules)
|
63
42
|
modules.to_a.flatten.compact.map do |object|
|
64
43
|
mod = get_module(object)
|
@@ -81,6 +60,33 @@ module FriendlyId
|
|
81
60
|
base.to_s
|
82
61
|
end
|
83
62
|
|
63
|
+
# The base column or method used by FriendlyId as the basis of a friendly id
|
64
|
+
# or slug.
|
65
|
+
#
|
66
|
+
# For models that don't use {FriendlyId::Slugged}, this is the column that
|
67
|
+
# is used to store the friendly id. For models using {FriendlyId::Slugged},
|
68
|
+
# the base is a column or method whose value is used as the basis of the
|
69
|
+
# slug.
|
70
|
+
#
|
71
|
+
# For example, if you have a model representing blog posts and that uses
|
72
|
+
# slugs, you likely will want to use the "title" attribute as the base, and
|
73
|
+
# FriendlyId will take care of transforming the human-readable title into
|
74
|
+
# something suitable for use in a URL.
|
75
|
+
#
|
76
|
+
# If you pass an argument, it will be used as the base. Otherwise the current
|
77
|
+
# value is returned.
|
78
|
+
#
|
79
|
+
# @param value A symbol referencing a column or method in the model. This
|
80
|
+
# value is usually set by passing it as the first argument to
|
81
|
+
# {FriendlyId::Base#friendly_id friendly_id}.
|
82
|
+
def base(*value)
|
83
|
+
if value.empty?
|
84
|
+
@base
|
85
|
+
else
|
86
|
+
self.base = value.first
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
84
90
|
private
|
85
91
|
|
86
92
|
def get_module(object)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# FriendlyId Global Configuration
|
2
|
+
#
|
3
|
+
# Use this to set up shared configuration options for your entire application.
|
4
|
+
# Any of the configuration options shown here can also be applied to single
|
5
|
+
# models by passing arguments to the `friendly_id` class method or defining
|
6
|
+
# methods in your model.
|
7
|
+
#
|
8
|
+
# To learn more, check out the guide:
|
9
|
+
#
|
10
|
+
# http://rubydoc.info/github/norman/friendly_id/master/file/Guide.md
|
11
|
+
|
12
|
+
FriendlyId.defaults do |config|
|
13
|
+
# ## Reserved Words
|
14
|
+
#
|
15
|
+
# Some words could conflict with Rails's routes when used as slugs, or are
|
16
|
+
# undesirable to allow as slugs. Edit this list as needed for your app.
|
17
|
+
config.use :reserved
|
18
|
+
|
19
|
+
config.reserved_words = %w(new edit index session login logout users admin
|
20
|
+
stylesheets assets javascripts images)
|
21
|
+
|
22
|
+
# ## Friendly Finders
|
23
|
+
#
|
24
|
+
# Uncomment this to use friendly finders in all models. By default, if
|
25
|
+
# you wish to find a record by its friendly id, you must do:
|
26
|
+
#
|
27
|
+
# MyModel.friendly.find('foo')
|
28
|
+
#
|
29
|
+
# If you uncomment this, you can do:
|
30
|
+
#
|
31
|
+
# MyModel.find('foo')
|
32
|
+
#
|
33
|
+
# This is significantly more convenient but may not be appropriate for
|
34
|
+
# all applications, so you must explicity opt-in to this behavior. You can
|
35
|
+
# always also configure it on a per-model basis if you prefer.
|
36
|
+
#
|
37
|
+
# config.use :finders
|
38
|
+
#
|
39
|
+
# ## Slugs
|
40
|
+
#
|
41
|
+
# Most applications will use the :slugged module everywhere. If you wish
|
42
|
+
# to do so, uncomment the following line.
|
43
|
+
#
|
44
|
+
# config.use :slugged
|
45
|
+
#
|
46
|
+
# By default, FriendlyId's :slugged addon expects the slug column to be named
|
47
|
+
# 'slug', but you can change it if you wish.
|
48
|
+
#
|
49
|
+
# config.slug_column = 'slug'
|
50
|
+
#
|
51
|
+
# When FriendlyId can not generate a unique ID from your base method, it appends
|
52
|
+
# a UUID, separated by a single dash. You can configure the character used as the
|
53
|
+
# separator. If you're upgrading from FriendlyId 4, you may wish to replace this
|
54
|
+
# with two dashes.
|
55
|
+
#
|
56
|
+
# config.sequence_separator = '-'
|
57
|
+
#
|
58
|
+
# ## Tips and Tricks
|
59
|
+
#
|
60
|
+
# ### Controlling when slugs are generated
|
61
|
+
#
|
62
|
+
# As of FriendlyId 5.0, new slugs are generated only when the slug field is
|
63
|
+
# nil, but you if you're using a column as your base method can change this
|
64
|
+
# behavior by overriding the `should_generate_new_friendly_id` method that
|
65
|
+
# FriendlyId adds to your model. The change below makes FriendlyId 5.0 behave
|
66
|
+
# more like 4.0.
|
67
|
+
#
|
68
|
+
# config.use Module.new {
|
69
|
+
# def should_generate_new_friendly_id?
|
70
|
+
# slug.blank? || <your_column_name_here>_changed?
|
71
|
+
# end
|
72
|
+
# }
|
73
|
+
#
|
74
|
+
# FriendlyId uses Rails's `parameterize` method to generate slugs, but for
|
75
|
+
# languages that don't use the Roman alphabet, that's not usually suffient. Here
|
76
|
+
# we use the Babosa library to transliterate Russian Cyrillic slugs to ASCII. If
|
77
|
+
# you use this, don't forget to add "babosa" to your Gemfile.
|
78
|
+
#
|
79
|
+
# config.use Module.new {
|
80
|
+
# def normalize_friendly_id(text)
|
81
|
+
# text.to_slug.normalize! :transliterations => [:russian, :latin]
|
82
|
+
# end
|
83
|
+
# }
|
84
|
+
end
|
data/lib/friendly_id/reserved.rb
CHANGED
@@ -7,21 +7,15 @@ module FriendlyId
|
|
7
7
|
The {FriendlyId::Reserved Reserved} module adds the ability to exlude a list of
|
8
8
|
words from use as FriendlyId slugs.
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
FriendlyId.defaults}
|
10
|
+
With Ruby on Rails, FriendlyId's generator generates an initializer that
|
11
|
+
reserves some words such as "new" and "edit" using {FriendlyId.defaults
|
12
|
+
FriendlyId.defaults}.
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
Note that the error message will appear on the field `:friendly_id`. If you are
|
21
|
-
using Rails's scaffolded form errors display, then it will have no field to
|
22
|
-
highlight. If you'd like to change this so that scaffolding works as expected,
|
23
|
-
one way to accomplish this is to move the error message to a different field.
|
24
|
-
For example:
|
14
|
+
Note that the error messages for fields will appear on the field
|
15
|
+
`:friendly_id`. If you are using Rails's scaffolded form errors display, then
|
16
|
+
it will have no field to highlight. If you'd like to change this so that
|
17
|
+
scaffolding works as expected, one way to accomplish this is to move the error
|
18
|
+
message to a different field. For example:
|
25
19
|
|
26
20
|
class Person < ActiveRecord::Base
|
27
21
|
extend FriendlyId
|
@@ -42,27 +36,16 @@ For example:
|
|
42
36
|
def self.included(model_class)
|
43
37
|
model_class.class_eval do
|
44
38
|
friendly_id_config.class.send :include, Reserved::Configuration
|
45
|
-
|
39
|
+
validates_exclusion_of :friendly_id, :in => ->(_) {
|
40
|
+
friendly_id_config.reserved_words || []
|
41
|
+
}
|
46
42
|
end
|
47
43
|
end
|
48
44
|
|
49
45
|
# This module adds the `:reserved_words` configuration option to
|
50
46
|
# {FriendlyId::Configuration FriendlyId::Configuration}.
|
51
47
|
module Configuration
|
52
|
-
|
53
|
-
|
54
|
-
# Overrides {FriendlyId::Configuration#base} to add a validation to the
|
55
|
-
# model class.
|
56
|
-
def base=(base)
|
57
|
-
super
|
58
|
-
reserved_words = model_class.friendly_id_config.reserved_words
|
59
|
-
model_class.validates_exclusion_of :friendly_id, :in => reserved_words
|
60
|
-
end
|
61
|
-
|
62
|
-
# An array of words forbidden as slugs.
|
63
|
-
def reserved_words
|
64
|
-
@reserved_words ||= @defaults[:reserved_words]
|
65
|
-
end
|
48
|
+
attr_accessor :reserved_words
|
66
49
|
end
|
67
50
|
end
|
68
51
|
end
|
data/lib/friendly_id/slugged.rb
CHANGED
@@ -298,7 +298,12 @@ Github issue](https://github.com/norman/friendly_id/issues/185) for discussion.
|
|
298
298
|
private :set_slug
|
299
299
|
|
300
300
|
def slug_generator
|
301
|
-
|
301
|
+
scope = self.class.base_class.unscoped.friendly
|
302
|
+
if changed.include?(friendly_id_config.slug_column)
|
303
|
+
column = self.class.quoted_table_name + '.' + self.class.quoted_primary_key
|
304
|
+
scope = scope.where("#{column} <> ?", send(self.class.primary_key))
|
305
|
+
end
|
306
|
+
friendly_id_config.slug_generator_class.new(scope)
|
302
307
|
end
|
303
308
|
private :slug_generator
|
304
309
|
|
data/lib/friendly_id/version.rb
CHANGED
@@ -8,11 +8,19 @@ class FriendlyIdGenerator < ActiveRecord::Generators::Base
|
|
8
8
|
# new table name. Our generator always uses 'friendly_id_slugs', so we just set a random name here.
|
9
9
|
argument :name, type: :string, default: 'random_name'
|
10
10
|
|
11
|
+
class_option :'skip-migration', :type => :boolean, :desc => "Don't generate a migration for the slugs table"
|
12
|
+
class_option :'skip-initializer', :type => :boolean, :desc => "Don't generate an initializer"
|
13
|
+
|
11
14
|
source_root File.expand_path('../../friendly_id', __FILE__)
|
12
15
|
|
13
16
|
# Copies the migration template to db/migrate.
|
14
17
|
def copy_files
|
18
|
+
return if options['skip-migration']
|
15
19
|
migration_template 'migration.rb', 'db/migrate/create_friendly_id_slugs.rb'
|
16
20
|
end
|
17
21
|
|
22
|
+
def create_initializer
|
23
|
+
return if options['skip-initializer']
|
24
|
+
copy_file 'initializer.rb', 'config/initializers/friendly_id.rb'
|
25
|
+
end
|
18
26
|
end
|
data/test/configuration_test.rb
CHANGED
@@ -45,4 +45,20 @@ class ConfigurationTest < MiniTest::Unit::TestCase
|
|
45
45
|
assert @model_class < my_module
|
46
46
|
end
|
47
47
|
|
48
|
+
test "#base should optionally set a value" do
|
49
|
+
config = FriendlyId::Configuration.new @model_class
|
50
|
+
assert_nil config.base
|
51
|
+
config.base = 'foo'
|
52
|
+
assert_equal 'foo', config.base
|
53
|
+
end
|
54
|
+
|
55
|
+
test "#base can set the value to nil" do
|
56
|
+
config = FriendlyId::Configuration.new @model_class
|
57
|
+
config.base 'foo'
|
58
|
+
config.base nil
|
59
|
+
assert_nil config.base
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
48
64
|
end
|
data/test/generator_test.rb
CHANGED
@@ -17,4 +17,32 @@ class FriendlyIdGeneratorTest < Rails::Generators::TestCase
|
|
17
17
|
FileUtils.rm_rf self.destination_root
|
18
18
|
end
|
19
19
|
end
|
20
|
+
|
21
|
+
test "should skip the migration when told to do so" do
|
22
|
+
begin
|
23
|
+
run_generator ['--skip-migration']
|
24
|
+
assert_no_migration "db/migrate/create_friendly_id_slugs"
|
25
|
+
ensure
|
26
|
+
FileUtils.rm_rf self.destination_root
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
test "should generate an initializer" do
|
31
|
+
begin
|
32
|
+
run_generator
|
33
|
+
assert_file "config/initializers/friendly_id.rb"
|
34
|
+
ensure
|
35
|
+
FileUtils.rm_rf self.destination_root
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should skip the initializer when told to do so" do
|
40
|
+
begin
|
41
|
+
run_generator ['--skip-initializer']
|
42
|
+
assert_no_file "config/initializers/friendly_id.rb"
|
43
|
+
ensure
|
44
|
+
FileUtils.rm_rf self.destination_root
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
20
48
|
end
|
data/test/reserved_test.rb
CHANGED
@@ -6,7 +6,7 @@ class ReservedTest < MiniTest::Unit::TestCase
|
|
6
6
|
|
7
7
|
class Journalist < ActiveRecord::Base
|
8
8
|
extend FriendlyId
|
9
|
-
friendly_id :name
|
9
|
+
friendly_id :name, :use => [:slugged, :reserved], :reserved_words => %w(new edit)
|
10
10
|
|
11
11
|
after_validation :move_friendly_id_error_to_name
|
12
12
|
|
@@ -19,8 +19,8 @@ class ReservedTest < MiniTest::Unit::TestCase
|
|
19
19
|
Journalist
|
20
20
|
end
|
21
21
|
|
22
|
-
test "should reserve
|
23
|
-
%w(new edit).each do |word|
|
22
|
+
test "should reserve words" do
|
23
|
+
%w(new edit NEW Edit).each do |word|
|
24
24
|
transaction do
|
25
25
|
assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
|
26
26
|
end
|
data/test/slugged_test.rb
CHANGED
@@ -29,14 +29,6 @@ class SluggedTest < MiniTest::Unit::TestCase
|
|
29
29
|
Journalist
|
30
30
|
end
|
31
31
|
|
32
|
-
test "should not allow reserved words in resulting slug" do
|
33
|
-
["new", "New", "NEW"].each do |word|
|
34
|
-
transaction do
|
35
|
-
assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
32
|
test "should allow validations on the slug" do
|
41
33
|
model_class = Class.new(ActiveRecord::Base) do
|
42
34
|
self.table_name = "articles"
|
@@ -76,6 +68,15 @@ class SluggedTest < MiniTest::Unit::TestCase
|
|
76
68
|
refute instance2.valid?
|
77
69
|
end
|
78
70
|
end
|
71
|
+
|
72
|
+
test 'should allow a record to reuse its own slug' do
|
73
|
+
with_instance_of(model_class) do |record|
|
74
|
+
old_id = record.friendly_id
|
75
|
+
record.slug = nil
|
76
|
+
record.save!
|
77
|
+
assert_equal old_id, record.friendly_id
|
78
|
+
end
|
79
|
+
end
|
79
80
|
end
|
80
81
|
|
81
82
|
class SlugGeneratorTest < MiniTest::Unit::TestCase
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: friendly_id
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.0.
|
4
|
+
version: 5.0.0.beta4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Norman Clarke
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -170,6 +170,7 @@ files:
|
|
170
170
|
- lib/friendly_id/finder_methods.rb
|
171
171
|
- lib/friendly_id/finders.rb
|
172
172
|
- lib/friendly_id/history.rb
|
173
|
+
- lib/friendly_id/initializer.rb
|
173
174
|
- lib/friendly_id/migration.rb
|
174
175
|
- lib/friendly_id/object_utils.rb
|
175
176
|
- lib/friendly_id/reserved.rb
|