friendly_id 5.4.1 → 5.5.1
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
- checksums.yaml.gz.sig +0 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/test.yml +38 -36
- data/.yardopts +2 -0
- data/Changelog.md +15 -0
- data/Gemfile +9 -13
- data/README.md +21 -0
- data/Rakefile +24 -27
- data/bench.rb +30 -27
- data/certs/parndt.pem +25 -23
- data/friendly_id.gemspec +26 -29
- data/gemfiles/Gemfile.rails-5.2.rb +11 -16
- data/gemfiles/Gemfile.rails-6.0.rb +11 -16
- data/gemfiles/Gemfile.rails-6.1.rb +22 -0
- data/gemfiles/Gemfile.rails-7.0.rb +22 -0
- data/guide.rb +13 -6
- data/lib/friendly_id/base.rb +59 -60
- data/lib/friendly_id/candidates.rb +9 -11
- data/lib/friendly_id/configuration.rb +6 -7
- data/lib/friendly_id/finder_methods.rb +63 -15
- data/lib/friendly_id/finders.rb +66 -66
- data/lib/friendly_id/history.rb +62 -63
- data/lib/friendly_id/initializer.rb +4 -4
- data/lib/friendly_id/migration.rb +6 -6
- data/lib/friendly_id/object_utils.rb +2 -2
- data/lib/friendly_id/reserved.rb +30 -32
- data/lib/friendly_id/scoped.rb +99 -102
- data/lib/friendly_id/sequentially_slugged/calculator.rb +69 -0
- data/lib/friendly_id/sequentially_slugged.rb +17 -64
- data/lib/friendly_id/simple_i18n.rb +78 -69
- data/lib/friendly_id/slug.rb +1 -2
- data/lib/friendly_id/slug_generator.rb +1 -3
- data/lib/friendly_id/slugged.rb +237 -238
- data/lib/friendly_id/version.rb +1 -1
- data/lib/friendly_id.rb +47 -49
- data/lib/generators/friendly_id_generator.rb +9 -9
- data/test/base_test.rb +10 -13
- data/test/benchmarks/finders.rb +28 -26
- data/test/benchmarks/object_utils.rb +13 -13
- data/test/candidates_test.rb +17 -18
- data/test/configuration_test.rb +7 -11
- data/test/core_test.rb +1 -2
- data/test/databases.yml +4 -3
- data/test/finders_test.rb +36 -13
- data/test/generator_test.rb +16 -26
- data/test/helper.rb +31 -24
- data/test/history_test.rb +70 -74
- data/test/numeric_slug_test.rb +4 -4
- data/test/object_utils_test.rb +0 -2
- data/test/reserved_test.rb +9 -11
- data/test/schema.rb +5 -4
- data/test/scoped_test.rb +18 -20
- data/test/sequentially_slugged_test.rb +65 -50
- data/test/shared.rb +15 -16
- data/test/simple_i18n_test.rb +22 -12
- data/test/slugged_test.rb +125 -113
- data/test/sti_test.rb +19 -21
- data.tar.gz.sig +0 -0
- metadata +37 -32
- metadata.gz.sig +0 -0
data/lib/friendly_id/slugged.rb
CHANGED
@@ -1,253 +1,252 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
require "friendly_id/slug_generator"
|
3
2
|
require "friendly_id/candidates"
|
4
3
|
|
5
4
|
module FriendlyId
|
6
|
-
|
7
|
-
|
8
|
-
## Slugged Models
|
9
|
-
|
10
|
-
FriendlyId can use a separate column to store slugs for models which require
|
11
|
-
some text processing.
|
12
|
-
|
13
|
-
For example, blog applications typically use a post title to provide the basis
|
14
|
-
of a search engine friendly URL. Such identifiers typically lack uppercase
|
15
|
-
characters, use ASCII to approximate UTF-8 characters, and strip out other
|
16
|
-
characters which may make them aesthetically unappealing or error-prone when
|
17
|
-
used in a URL.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
In general, use slugs by default unless you know for sure you don't need them.
|
29
|
-
To activate the slugging functionality, use the {FriendlyId::Slugged} module.
|
30
|
-
|
31
|
-
FriendlyId will generate slugs from a method or column that you specify, and
|
32
|
-
store them in a field in your model. By default, this field must be named
|
33
|
-
`:slug`, though you may change this using the
|
34
|
-
{FriendlyId::Slugged::Configuration#slug_column slug_column} configuration
|
35
|
-
option. You should add an index to this column, and in most cases, make it
|
36
|
-
unique. You may also wish to constrain it to NOT NULL, but this depends on your
|
37
|
-
app's behavior and requirements.
|
38
|
-
|
39
|
-
### Example Setup
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
### Working With Slugs
|
66
|
-
|
67
|
-
#### Formatting
|
68
|
-
|
69
|
-
By default, FriendlyId uses Active Support's
|
70
|
-
[parameterize](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize)
|
71
|
-
method to create slugs. This method will intelligently replace spaces with
|
72
|
-
dashes, and Unicode Latin characters with ASCII approximations:
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
#### Column or Method?
|
78
|
-
|
79
|
-
FriendlyId always uses a method as the basis of the slug text - not a column. At
|
80
|
-
first glance, this may sound confusing, but remember that Active Record provides
|
81
|
-
methods for each column in a model's associated table, and that's what
|
82
|
-
FriendlyId uses.
|
83
|
-
|
84
|
-
Here's an example of a class that uses a custom method to generate the slug:
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
FriendlyId refers to this internally as the "base" method.
|
99
|
-
|
100
|
-
#### Uniqueness
|
101
|
-
|
102
|
-
When you try to insert a record that would generate a duplicate friendly id,
|
103
|
-
FriendlyId will append a UUID to the generated slug to ensure uniqueness:
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
Previous versions of FriendlyId appended a numeric sequence to make slugs
|
112
|
-
unique, but this was removed to simplify using FriendlyId in concurrent code.
|
113
|
-
|
114
|
-
#### Candidates
|
115
|
-
|
116
|
-
Since UUIDs are ugly, FriendlyId provides a "slug candidates" functionality to
|
117
|
-
let you specify alternate slugs to use in the event the one you want to use is
|
118
|
-
already taken. For example:
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
To use candidates, make your FriendlyId base method return an array. The
|
143
|
-
method need not be named `slug_candidates`; it can be anything you want. The
|
144
|
-
array may contain any combination of symbols, strings, procs or lambdas and
|
145
|
-
will be evaluated lazily and in order. If you include symbols, FriendlyId will
|
146
|
-
invoke a method on your model class with the same name. Strings will be
|
147
|
-
interpreted literally. Procs and lambdas will be called and their return values
|
148
|
-
used as the basis of the friendly id. If none of the candidates can generate a
|
149
|
-
unique slug, then FriendlyId will append a UUID to the first candidate as a
|
150
|
-
last resort.
|
151
|
-
|
152
|
-
#### Sequence Separator
|
153
|
-
|
154
|
-
By default, FriendlyId uses a dash to separate the slug from a sequence.
|
155
|
-
|
156
|
-
You can change this with the {FriendlyId::Slugged::Configuration#sequence_separator
|
157
|
-
sequence_separator} configuration option.
|
158
|
-
|
159
|
-
#### Providing Your Own Slug Processing Method
|
160
|
-
|
161
|
-
You can override {FriendlyId::Slugged#normalize_friendly_id} in your model for
|
162
|
-
total control over the slug format. It will be invoked for any generated slug,
|
163
|
-
whether for a single slug or for slug candidates.
|
164
|
-
|
165
|
-
#### Deciding When to Generate New Slugs
|
166
|
-
|
167
|
-
As of FriendlyId 5.0, slugs are only generated when the `slug` field is nil. If
|
168
|
-
you want a slug to be regenerated,set the slug field to nil:
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
You can also override the
|
179
|
-
{FriendlyId::Slugged#should_generate_new_friendly_id?} method, which lets you
|
180
|
-
control exactly when new friendly ids are set:
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
If you want to extend the default behavior but add your own conditions,
|
192
|
-
don't forget to invoke `super` from your implementation:
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
#### Locale-specific Transliterations
|
204
|
-
|
205
|
-
Active Support's `parameterize` uses
|
206
|
-
[transliterate](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate),
|
207
|
-
which in turn can use I18n's transliteration rules to consider the current
|
208
|
-
locale when replacing Latin characters:
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
This functionality was in fact taken from earlier versions of FriendlyId.
|
223
|
-
|
224
|
-
#### Gotchas: Common Problems
|
225
|
-
|
226
|
-
FriendlyId uses a before_validation callback to generate and set the slug. This
|
227
|
-
means that if you create two model instances before saving them, it's possible
|
228
|
-
they will generate the same slug, and the second save will fail.
|
229
|
-
|
230
|
-
This can happen in two fairly normal cases: the first, when a model using nested
|
231
|
-
attributes creates more than one record for a model that uses friendly_id. The
|
232
|
-
second, in concurrent code, either in threads or multiple processes.
|
233
|
-
|
234
|
-
To solve the nested attributes issue, I recommend simply avoiding them when
|
235
|
-
creating more than one nested record for a model that uses FriendlyId. See [this
|
236
|
-
Github issue](https://github.com/norman/friendly_id/issues/185) for discussion.
|
237
|
-
|
238
|
-
|
5
|
+
# @guide begin
|
6
|
+
#
|
7
|
+
# ## Slugged Models
|
8
|
+
#
|
9
|
+
# FriendlyId can use a separate column to store slugs for models which require
|
10
|
+
# some text processing.
|
11
|
+
#
|
12
|
+
# For example, blog applications typically use a post title to provide the basis
|
13
|
+
# of a search engine friendly URL. Such identifiers typically lack uppercase
|
14
|
+
# characters, use ASCII to approximate UTF-8 characters, and strip out other
|
15
|
+
# characters which may make them aesthetically unappealing or error-prone when
|
16
|
+
# used in a URL.
|
17
|
+
#
|
18
|
+
# class Post < ActiveRecord::Base
|
19
|
+
# extend FriendlyId
|
20
|
+
# friendly_id :title, :use => :slugged
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @post = Post.create(:title => "This is the first post!")
|
24
|
+
# @post.friendly_id # returns "this-is-the-first-post"
|
25
|
+
# redirect_to @post # the URL will be /posts/this-is-the-first-post
|
26
|
+
#
|
27
|
+
# In general, use slugs by default unless you know for sure you don't need them.
|
28
|
+
# To activate the slugging functionality, use the {FriendlyId::Slugged} module.
|
29
|
+
#
|
30
|
+
# FriendlyId will generate slugs from a method or column that you specify, and
|
31
|
+
# store them in a field in your model. By default, this field must be named
|
32
|
+
# `:slug`, though you may change this using the
|
33
|
+
# {FriendlyId::Slugged::Configuration#slug_column slug_column} configuration
|
34
|
+
# option. You should add an index to this column, and in most cases, make it
|
35
|
+
# unique. You may also wish to constrain it to NOT NULL, but this depends on your
|
36
|
+
# app's behavior and requirements.
|
37
|
+
#
|
38
|
+
# ### Example Setup
|
39
|
+
#
|
40
|
+
# # your model
|
41
|
+
# class Post < ActiveRecord::Base
|
42
|
+
# extend FriendlyId
|
43
|
+
# friendly_id :title, :use => :slugged
|
44
|
+
# validates_presence_of :title, :slug, :body
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # a migration
|
48
|
+
# class CreatePosts < ActiveRecord::Migration
|
49
|
+
# def self.up
|
50
|
+
# create_table :posts do |t|
|
51
|
+
# t.string :title, :null => false
|
52
|
+
# t.string :slug, :null => false
|
53
|
+
# t.text :body
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# add_index :posts, :slug, :unique => true
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# def self.down
|
60
|
+
# drop_table :posts
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# ### Working With Slugs
|
65
|
+
#
|
66
|
+
# #### Formatting
|
67
|
+
#
|
68
|
+
# By default, FriendlyId uses Active Support's
|
69
|
+
# [parameterize](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize)
|
70
|
+
# method to create slugs. This method will intelligently replace spaces with
|
71
|
+
# dashes, and Unicode Latin characters with ASCII approximations:
|
72
|
+
#
|
73
|
+
# movie = Movie.create! :title => "Der Preis fürs Überleben"
|
74
|
+
# movie.slug #=> "der-preis-furs-uberleben"
|
75
|
+
#
|
76
|
+
# #### Column or Method?
|
77
|
+
#
|
78
|
+
# FriendlyId always uses a method as the basis of the slug text - not a column. At
|
79
|
+
# first glance, this may sound confusing, but remember that Active Record provides
|
80
|
+
# methods for each column in a model's associated table, and that's what
|
81
|
+
# FriendlyId uses.
|
82
|
+
#
|
83
|
+
# Here's an example of a class that uses a custom method to generate the slug:
|
84
|
+
#
|
85
|
+
# class Person < ActiveRecord::Base
|
86
|
+
# extend FriendlyId
|
87
|
+
# friendly_id :name_and_location, use: :slugged
|
88
|
+
#
|
89
|
+
# def name_and_location
|
90
|
+
# "#{name} from #{location}"
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# bob = Person.create! :name => "Bob Smith", :location => "New York City"
|
95
|
+
# bob.friendly_id #=> "bob-smith-from-new-york-city"
|
96
|
+
#
|
97
|
+
# FriendlyId refers to this internally as the "base" method.
|
98
|
+
#
|
99
|
+
# #### Uniqueness
|
100
|
+
#
|
101
|
+
# When you try to insert a record that would generate a duplicate friendly id,
|
102
|
+
# FriendlyId will append a UUID to the generated slug to ensure uniqueness:
|
103
|
+
#
|
104
|
+
# car = Car.create :title => "Peugeot 206"
|
105
|
+
# car2 = Car.create :title => "Peugeot 206"
|
106
|
+
#
|
107
|
+
# car.friendly_id #=> "peugeot-206"
|
108
|
+
# car2.friendly_id #=> "peugeot-206-f9f3789a-daec-4156-af1d-fab81aa16ee5"
|
109
|
+
#
|
110
|
+
# Previous versions of FriendlyId appended a numeric sequence to make slugs
|
111
|
+
# unique, but this was removed to simplify using FriendlyId in concurrent code.
|
112
|
+
#
|
113
|
+
# #### Candidates
|
114
|
+
#
|
115
|
+
# Since UUIDs are ugly, FriendlyId provides a "slug candidates" functionality to
|
116
|
+
# let you specify alternate slugs to use in the event the one you want to use is
|
117
|
+
# already taken. For example:
|
118
|
+
#
|
119
|
+
# class Restaurant < ActiveRecord::Base
|
120
|
+
# extend FriendlyId
|
121
|
+
# friendly_id :slug_candidates, use: :slugged
|
122
|
+
#
|
123
|
+
# # Try building a slug based on the following fields in
|
124
|
+
# # increasing order of specificity.
|
125
|
+
# def slug_candidates
|
126
|
+
# [
|
127
|
+
# :name,
|
128
|
+
# [:name, :city],
|
129
|
+
# [:name, :street, :city],
|
130
|
+
# [:name, :street_number, :street, :city]
|
131
|
+
# ]
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# r1 = Restaurant.create! name: 'Plaza Diner', city: 'New Paltz'
|
136
|
+
# r2 = Restaurant.create! name: 'Plaza Diner', city: 'Kingston'
|
137
|
+
#
|
138
|
+
# r1.friendly_id #=> 'plaza-diner'
|
139
|
+
# r2.friendly_id #=> 'plaza-diner-kingston'
|
140
|
+
#
|
141
|
+
# To use candidates, make your FriendlyId base method return an array. The
|
142
|
+
# method need not be named `slug_candidates`; it can be anything you want. The
|
143
|
+
# array may contain any combination of symbols, strings, procs or lambdas and
|
144
|
+
# will be evaluated lazily and in order. If you include symbols, FriendlyId will
|
145
|
+
# invoke a method on your model class with the same name. Strings will be
|
146
|
+
# interpreted literally. Procs and lambdas will be called and their return values
|
147
|
+
# used as the basis of the friendly id. If none of the candidates can generate a
|
148
|
+
# unique slug, then FriendlyId will append a UUID to the first candidate as a
|
149
|
+
# last resort.
|
150
|
+
#
|
151
|
+
# #### Sequence Separator
|
152
|
+
#
|
153
|
+
# By default, FriendlyId uses a dash to separate the slug from a sequence.
|
154
|
+
#
|
155
|
+
# You can change this with the {FriendlyId::Slugged::Configuration#sequence_separator
|
156
|
+
# sequence_separator} configuration option.
|
157
|
+
#
|
158
|
+
# #### Providing Your Own Slug Processing Method
|
159
|
+
#
|
160
|
+
# You can override {FriendlyId::Slugged#normalize_friendly_id} in your model for
|
161
|
+
# total control over the slug format. It will be invoked for any generated slug,
|
162
|
+
# whether for a single slug or for slug candidates.
|
163
|
+
#
|
164
|
+
# #### Deciding When to Generate New Slugs
|
165
|
+
#
|
166
|
+
# As of FriendlyId 5.0, slugs are only generated when the `slug` field is nil. If
|
167
|
+
# you want a slug to be regenerated,set the slug field to nil:
|
168
|
+
#
|
169
|
+
# restaurant.friendly_id # joes-diner
|
170
|
+
# restaurant.name = "The Plaza Diner"
|
171
|
+
# restaurant.save!
|
172
|
+
# restaurant.friendly_id # joes-diner
|
173
|
+
# restaurant.slug = nil
|
174
|
+
# restaurant.save!
|
175
|
+
# restaurant.friendly_id # the-plaza-diner
|
176
|
+
#
|
177
|
+
# You can also override the
|
178
|
+
# {FriendlyId::Slugged#should_generate_new_friendly_id?} method, which lets you
|
179
|
+
# control exactly when new friendly ids are set:
|
180
|
+
#
|
181
|
+
# class Post < ActiveRecord::Base
|
182
|
+
# extend FriendlyId
|
183
|
+
# friendly_id :title, :use => :slugged
|
184
|
+
#
|
185
|
+
# def should_generate_new_friendly_id?
|
186
|
+
# title_changed?
|
187
|
+
# end
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# If you want to extend the default behavior but add your own conditions,
|
191
|
+
# don't forget to invoke `super` from your implementation:
|
192
|
+
#
|
193
|
+
# class Category < ActiveRecord::Base
|
194
|
+
# extend FriendlyId
|
195
|
+
# friendly_id :name, :use => :slugged
|
196
|
+
#
|
197
|
+
# def should_generate_new_friendly_id?
|
198
|
+
# name_changed? || super
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# #### Locale-specific Transliterations
|
203
|
+
#
|
204
|
+
# Active Support's `parameterize` uses
|
205
|
+
# [transliterate](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate),
|
206
|
+
# which in turn can use I18n's transliteration rules to consider the current
|
207
|
+
# locale when replacing Latin characters:
|
208
|
+
#
|
209
|
+
# # config/locales/de.yml
|
210
|
+
# de:
|
211
|
+
# i18n:
|
212
|
+
# transliterate:
|
213
|
+
# rule:
|
214
|
+
# ü: "ue"
|
215
|
+
# ö: "oe"
|
216
|
+
# etc...
|
217
|
+
#
|
218
|
+
# movie = Movie.create! :title => "Der Preis fürs Überleben"
|
219
|
+
# movie.slug #=> "der-preis-fuers-ueberleben"
|
220
|
+
#
|
221
|
+
# This functionality was in fact taken from earlier versions of FriendlyId.
|
222
|
+
#
|
223
|
+
# #### Gotchas: Common Problems
|
224
|
+
#
|
225
|
+
# FriendlyId uses a before_validation callback to generate and set the slug. This
|
226
|
+
# means that if you create two model instances before saving them, it's possible
|
227
|
+
# they will generate the same slug, and the second save will fail.
|
228
|
+
#
|
229
|
+
# This can happen in two fairly normal cases: the first, when a model using nested
|
230
|
+
# attributes creates more than one record for a model that uses friendly_id. The
|
231
|
+
# second, in concurrent code, either in threads or multiple processes.
|
232
|
+
#
|
233
|
+
# To solve the nested attributes issue, I recommend simply avoiding them when
|
234
|
+
# creating more than one nested record for a model that uses FriendlyId. See [this
|
235
|
+
# Github issue](https://github.com/norman/friendly_id/issues/185) for discussion.
|
236
|
+
#
|
237
|
+
# @guide end
|
239
238
|
module Slugged
|
240
|
-
|
241
239
|
# Sets up behavior and configuration options for FriendlyId's slugging
|
242
240
|
# feature.
|
243
241
|
def self.included(model_class)
|
244
242
|
model_class.friendly_id_config.instance_eval do
|
245
243
|
self.class.send :include, Configuration
|
246
|
-
self.slug_generator_class
|
247
|
-
defaults[:slug_column]
|
248
|
-
defaults[:sequence_separator] ||=
|
244
|
+
self.slug_generator_class ||= SlugGenerator
|
245
|
+
defaults[:slug_column] ||= "slug"
|
246
|
+
defaults[:sequence_separator] ||= "-"
|
249
247
|
end
|
250
248
|
model_class.before_validation :set_slug
|
249
|
+
model_class.before_save :set_slug
|
251
250
|
model_class.after_validation :unset_slug_if_invalid
|
252
251
|
end
|
253
252
|
|
data/lib/friendly_id/version.rb
CHANGED
data/lib/friendly_id.rb
CHANGED
@@ -1,55 +1,53 @@
|
|
1
|
-
|
2
|
-
require 'active_record'
|
1
|
+
require "active_record"
|
3
2
|
require "friendly_id/base"
|
4
3
|
require "friendly_id/object_utils"
|
5
4
|
require "friendly_id/configuration"
|
6
5
|
require "friendly_id/finder_methods"
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
## About FriendlyId
|
11
|
-
|
12
|
-
FriendlyId is an add-on to Ruby's Active Record that allows you to replace ids
|
13
|
-
in your URLs with strings:
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
It requires few changes to your application code and offers flexibility,
|
22
|
-
performance and a well-documented codebase.
|
23
|
-
|
24
|
-
### Core Concepts
|
25
|
-
|
26
|
-
#### Slugs
|
27
|
-
|
28
|
-
The concept of *slugs* is at the heart of FriendlyId.
|
29
|
-
|
30
|
-
A slug is the part of a URL which identifies a page using human-readable
|
31
|
-
keywords, rather than an opaque identifier such as a numeric id. This can make
|
32
|
-
your application more friendly both for users and search engines.
|
33
|
-
|
34
|
-
#### Finders: Slugs Act Like Numeric IDs
|
35
|
-
|
36
|
-
To the extent possible, FriendlyId lets you treat text-based identifiers like
|
37
|
-
normal IDs. This means that you can perform finds with slugs just like you do
|
38
|
-
with numeric ids:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
7
|
+
# @guide begin
|
8
|
+
#
|
9
|
+
# ## About FriendlyId
|
10
|
+
#
|
11
|
+
# FriendlyId is an add-on to Ruby's Active Record that allows you to replace ids
|
12
|
+
# in your URLs with strings:
|
13
|
+
#
|
14
|
+
# # without FriendlyId
|
15
|
+
# http://example.com/states/4323454
|
16
|
+
#
|
17
|
+
# # with FriendlyId
|
18
|
+
# http://example.com/states/washington
|
19
|
+
#
|
20
|
+
# It requires few changes to your application code and offers flexibility,
|
21
|
+
# performance and a well-documented codebase.
|
22
|
+
#
|
23
|
+
# ### Core Concepts
|
24
|
+
#
|
25
|
+
# #### Slugs
|
26
|
+
#
|
27
|
+
# The concept of *slugs* is at the heart of FriendlyId.
|
28
|
+
#
|
29
|
+
# A slug is the part of a URL which identifies a page using human-readable
|
30
|
+
# keywords, rather than an opaque identifier such as a numeric id. This can make
|
31
|
+
# your application more friendly both for users and search engines.
|
32
|
+
#
|
33
|
+
# #### Finders: Slugs Act Like Numeric IDs
|
34
|
+
#
|
35
|
+
# To the extent possible, FriendlyId lets you treat text-based identifiers like
|
36
|
+
# normal IDs. This means that you can perform finds with slugs just like you do
|
37
|
+
# with numeric ids:
|
38
|
+
#
|
39
|
+
# Person.find(82542335)
|
40
|
+
# Person.friendly.find("joe")
|
41
|
+
#
|
42
|
+
# @guide end
|
44
43
|
module FriendlyId
|
45
|
-
|
46
|
-
autoload :
|
47
|
-
autoload :
|
48
|
-
autoload :
|
49
|
-
autoload :
|
50
|
-
autoload :
|
51
|
-
autoload :
|
52
|
-
autoload :Finders, "friendly_id/finders"
|
44
|
+
autoload :History, "friendly_id/history"
|
45
|
+
autoload :Slug, "friendly_id/slug"
|
46
|
+
autoload :SimpleI18n, "friendly_id/simple_i18n"
|
47
|
+
autoload :Reserved, "friendly_id/reserved"
|
48
|
+
autoload :Scoped, "friendly_id/scoped"
|
49
|
+
autoload :Slugged, "friendly_id/slugged"
|
50
|
+
autoload :Finders, "friendly_id/finders"
|
53
51
|
autoload :SequentiallySlugged, "friendly_id/sequentially_slugged"
|
54
52
|
|
55
53
|
# FriendlyId takes advantage of `extended` to do basic model setup, primarily
|
@@ -77,7 +75,7 @@ module FriendlyId
|
|
77
75
|
def self.extended(model_class)
|
78
76
|
return if model_class.respond_to? :friendly_id
|
79
77
|
class << model_class
|
80
|
-
|
78
|
+
alias_method :relation_without_friendly_id, :relation
|
81
79
|
end
|
82
80
|
model_class.class_eval do
|
83
81
|
extend Base
|
@@ -102,8 +100,8 @@ module FriendlyId
|
|
102
100
|
# config.use :slugged
|
103
101
|
# end
|
104
102
|
def self.defaults(&block)
|
105
|
-
@defaults = block if
|
106
|
-
@defaults ||= ->(config) {config.use :reserved}
|
103
|
+
@defaults = block if block
|
104
|
+
@defaults ||= ->(config) { config.use :reserved }
|
107
105
|
end
|
108
106
|
|
109
107
|
# Set the ActiveRecord table name prefix to friendly_id_
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "rails/generators"
|
2
2
|
require "rails/generators/active_record"
|
3
3
|
|
4
4
|
# This generator adds a migration for the {FriendlyId::History
|
@@ -6,21 +6,21 @@ require "rails/generators/active_record"
|
|
6
6
|
class FriendlyIdGenerator < ActiveRecord::Generators::Base
|
7
7
|
# ActiveRecord::Generators::Base inherits from Rails::Generators::NamedBase which requires a NAME parameter for the
|
8
8
|
# new table name. Our generator always uses 'friendly_id_slugs', so we just set a random name here.
|
9
|
-
argument :name, type: :string, default:
|
9
|
+
argument :name, type: :string, default: "random_name"
|
10
10
|
|
11
|
-
class_option :'skip-migration', :
|
12
|
-
class_option :'skip-initializer', :
|
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
13
|
|
14
|
-
source_root File.expand_path(
|
14
|
+
source_root File.expand_path("../../friendly_id", __FILE__)
|
15
15
|
|
16
16
|
# Copies the migration template to db/migrate.
|
17
17
|
def copy_files
|
18
|
-
return if options[
|
19
|
-
migration_template
|
18
|
+
return if options["skip-migration"]
|
19
|
+
migration_template "migration.rb", "db/migrate/create_friendly_id_slugs.rb"
|
20
20
|
end
|
21
21
|
|
22
22
|
def create_initializer
|
23
|
-
return if options[
|
24
|
-
copy_file
|
23
|
+
return if options["skip-initializer"]
|
24
|
+
copy_file "initializer.rb", "config/initializers/friendly_id.rb"
|
25
25
|
end
|
26
26
|
end
|