friendly_id 5.0.0.beta3 → 5.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|