friendly_id 5.0.0.alpha.1 → 5.0.0.beta1
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/.yardopts +2 -1
- data/CONTRIBUTING.md +36 -0
- data/Changelog.md +14 -7
- data/{Guide.rdoc → Guide.md} +172 -155
- data/README.md +9 -8
- data/Rakefile +2 -3
- data/bench.rb +5 -3
- data/friendly_id.gemspec +9 -8
- data/lib/friendly_id.rb +7 -8
- data/lib/friendly_id/base.rb +31 -17
- data/lib/friendly_id/candidates.rb +4 -0
- data/lib/friendly_id/configuration.rb +4 -4
- data/lib/friendly_id/finders.rb +51 -0
- data/lib/friendly_id/history.rb +28 -18
- data/lib/friendly_id/object_utils.rb +7 -7
- data/lib/friendly_id/reserved.rb +3 -3
- data/lib/friendly_id/scoped.rb +19 -19
- data/lib/friendly_id/simple_i18n.rb +28 -28
- data/lib/friendly_id/slugged.rb +122 -101
- data/lib/friendly_id/version.rb +2 -2
- data/test/shared.rb +8 -0
- data/test/slugged_test.rb +1 -1
- metadata +19 -5
- data/WhatsNew.md +0 -3
- data/lib/friendly_id/scopes.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a7d80631aa03de549650e0cc84c04108204af5c
|
4
|
+
data.tar.gz: c868670182414c4846e8c4a94aa34d680f78c1a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 203a56c05ef6d18ab3ba8b9de406749a55689d25fb3776b744986c753bcd0a174ffe8f364521f5cca9255b7f196feea76f5fd94bde48c63d8bc4fb2e9a3f8ce9
|
7
|
+
data.tar.gz: 195f31cb8264650bb0b9922dc436575fa3ba33c4c0ecb8f4f2efb2c62033131f11e93d9ba9fff3c710b67bcd0dd96c5601e06a6b5cb9678e72b8abab6b985d2a
|
data/.yardopts
CHANGED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# FriendlyId
|
2
|
+
|
3
|
+
## Getting Help
|
4
|
+
|
5
|
+
Before opening a new issue, please search the existing issues to see if your
|
6
|
+
question has been answered before.
|
7
|
+
|
8
|
+
Please also take a look at the extensive documentation, especially the Guide.
|
9
|
+
|
10
|
+
## FAQ
|
11
|
+
|
12
|
+
Here are the answers to some common questions.
|
13
|
+
|
14
|
+
### I'm using Rails 4...
|
15
|
+
|
16
|
+
Then you **must** use FriendlyId 5, which is currently available in the master
|
17
|
+
branch of the repository, and will be released to Rubygems soon.
|
18
|
+
|
19
|
+
### How do I set up my routes for FriendlyId?
|
20
|
+
|
21
|
+
Exactly like in any other Rails app. FriendlyId doesn't change any routing
|
22
|
+
functionality, it only changes the ids that are shown in your routes.
|
23
|
+
|
24
|
+
TIP: Make your app work the way you want to with numeric id's. Then add
|
25
|
+
FriendlyId later.
|
26
|
+
|
27
|
+
### I'm seeing `undefined method `friendly_id'`
|
28
|
+
|
29
|
+
You probably just added the friendly_id gem. Run `bundle` and restart your
|
30
|
+
Rails app.
|
31
|
+
|
32
|
+
### I'm seeing `uninitialized constant FriendlyId`
|
33
|
+
|
34
|
+
You probably just added the friendly_id gem. Run `bundle` and restart your
|
35
|
+
Rails app.
|
36
|
+
|
data/Changelog.md
CHANGED
@@ -3,16 +3,23 @@
|
|
3
3
|
We would like to think our many {file:Contributors contributors} for
|
4
4
|
suggestions, ideas and improvements to FriendlyId.
|
5
5
|
|
6
|
-
|
7
|
-
{:toc}
|
6
|
+
## 5.0.0.beta1 (2013-08-10)
|
8
7
|
|
9
|
-
|
8
|
+
* Support for Rails 4.
|
9
|
+
* Made the :scoped and :history modules compatible with each other (Andre Duffeck).
|
10
|
+
* Removed class-level finders in favor of `friendly` scope (Norman Clarke).
|
11
|
+
* Implemented "candidates" support (Norman Clarke).
|
12
|
+
* Slug "sequences" are now GUIDs rather than numbers (Norman Clarke).
|
13
|
+
* `find` no longer falls back to super unless id is fully numeric string (Norman Clarke).
|
14
|
+
* Default sequence separator is now '-' rather than '--'.
|
15
|
+
* Support for Globalize has been removed until Globalize supports Rails 4.
|
16
|
+
* Removed upport for Ruby < 1.9.3 and Rails < 4.0.
|
10
17
|
|
11
|
-
Made the :scoped and :history modules compatible with each other (Andre Duffeck)
|
12
18
|
|
13
|
-
## 4.0.10 (
|
19
|
+
## 4.0.10 (2013-08-10)
|
14
20
|
|
15
|
-
* Fixed table prefixes/suffixes being ignored (Jesse Farless)
|
21
|
+
* Fixed table prefixes/suffixes being ignored (Jesse Farless).
|
22
|
+
* Fixed sequence generation for slugs containing numbers (Adam Carroll).
|
16
23
|
|
17
24
|
## 4.0.9 (2012-10-31)
|
18
25
|
|
@@ -38,7 +45,7 @@ Made the :scoped and :history modules compatible with each other (Andre Duffeck)
|
|
38
45
|
|
39
46
|
## 4.0.7 (2012-06-06)
|
40
47
|
|
41
|
-
* to_param just calls super when no
|
48
|
+
* to_param just calls super when no friendly id is present, to keep the model's
|
42
49
|
default behavior. (Andrew White)
|
43
50
|
|
44
51
|
* FriendlyId can now properly sequence slugs that end in numbers even when a
|
data/{Guide.rdoc → Guide.md}
RENAMED
@@ -1,7 +1,6 @@
|
|
1
|
-
#encoding: utf-8
|
2
1
|
|
3
2
|
|
4
|
-
|
3
|
+
## About FriendlyId
|
5
4
|
|
6
5
|
FriendlyId is an add-on to Ruby's Active Record that allows you to replace ids
|
7
6
|
in your URLs with strings:
|
@@ -15,28 +14,27 @@ in your URLs with strings:
|
|
15
14
|
It requires few changes to your application code and offers flexibility,
|
16
15
|
performance and a well-documented codebase.
|
17
16
|
|
18
|
-
|
17
|
+
### Core Concepts
|
19
18
|
|
20
|
-
|
19
|
+
#### Slugs
|
21
20
|
|
22
|
-
The concept of
|
23
|
-
the heart of FriendlyId.
|
21
|
+
The concept of *slugs* is at the heart of FriendlyId.
|
24
22
|
|
25
23
|
A slug is the part of a URL which identifies a page using human-readable
|
26
24
|
keywords, rather than an opaque identifier such as a numeric id. This can make
|
27
25
|
your application more friendly both for users and search engine.
|
28
26
|
|
29
|
-
|
27
|
+
#### Finders: Slugs Act Like Numeric IDs
|
30
28
|
|
31
29
|
To the extent possible, FriendlyId lets you treat text-based identifiers like
|
32
30
|
normal IDs. This means that you can perform finds with slugs just like you do
|
33
31
|
with numeric ids:
|
34
32
|
|
35
33
|
Person.find(82542335)
|
36
|
-
Person.find("joe")
|
34
|
+
Person.friendly.find("joe")
|
37
35
|
|
38
36
|
|
39
|
-
|
37
|
+
## Setting Up FriendlyId in Your Model
|
40
38
|
|
41
39
|
To use FriendlyId in your ActiveRecord models, you must first either extend or
|
42
40
|
include the FriendlyId module (it makes no difference), then invoke the
|
@@ -53,7 +51,7 @@ addons it should use. See the documentation for this method for a list of all
|
|
53
51
|
available addons, or skim through the rest of the docs to get a high-level
|
54
52
|
overview.
|
55
53
|
|
56
|
-
|
54
|
+
### The Default Setup: Simple Models
|
57
55
|
|
58
56
|
The simplest way to use FriendlyId is with a model that has a uniquely indexed
|
59
57
|
column with no spaces or special characters, and that is seldom or never
|
@@ -65,9 +63,9 @@ updated. The most common example of this is a user name:
|
|
65
63
|
validates_format_of :login, :with => /\A[a-z0-9]+\z/i
|
66
64
|
end
|
67
65
|
|
68
|
-
@user = User.find "joe" # the old User.find(1) still works, too
|
69
|
-
@user.to_param
|
70
|
-
redirect_to @user
|
66
|
+
@user = User.friendly.find "joe" # the old User.find(1) still works, too
|
67
|
+
@user.to_param # returns "joe"
|
68
|
+
redirect_to @user # the URL will be /users/joe
|
71
69
|
|
72
70
|
In this case, FriendlyId assumes you want to use the column as-is; it will never
|
73
71
|
modify the value of the column, and your application should ensure that the
|
@@ -78,7 +76,7 @@ value is unique and admissible in a URL:
|
|
78
76
|
friendly_id :name
|
79
77
|
end
|
80
78
|
|
81
|
-
@city.find "Viña del Mar"
|
79
|
+
@city.friendly.find "Viña del Mar"
|
82
80
|
redirect_to @city # the URL will be /cities/Viña%20del%20Mar
|
83
81
|
|
84
82
|
Writing the code to process an arbitrary string into a good identifier for use
|
@@ -86,7 +84,7 @@ in a URL can be repetitive and surprisingly tricky, so for this reason it's
|
|
86
84
|
often better and easier to use {FriendlyId::Slugged slugs}.
|
87
85
|
|
88
86
|
|
89
|
-
|
87
|
+
## Slugged Models
|
90
88
|
|
91
89
|
FriendlyId can use a separate column to store slugs for models which require
|
92
90
|
some text processing.
|
@@ -111,13 +109,13 @@ To activate the slugging functionality, use the {FriendlyId::Slugged} module.
|
|
111
109
|
|
112
110
|
FriendlyId will generate slugs from a method or column that you specify, and
|
113
111
|
store them in a field in your model. By default, this field must be named
|
114
|
-
|
112
|
+
`:slug`, though you may change this using the
|
115
113
|
{FriendlyId::Slugged::Configuration#slug_column slug_column} configuration
|
116
114
|
option. You should add an index to this column, and in most cases, make it
|
117
115
|
unique. You may also wish to constrain it to NOT NULL, but this depends on your
|
118
116
|
app's behavior and requirements.
|
119
117
|
|
120
|
-
|
118
|
+
### Example Setup
|
121
119
|
|
122
120
|
# your model
|
123
121
|
class Post < ActiveRecord::Base
|
@@ -143,119 +141,144 @@ app's behavior and requirements.
|
|
143
141
|
end
|
144
142
|
end
|
145
143
|
|
146
|
-
|
144
|
+
### Working With Slugs
|
147
145
|
|
148
|
-
|
146
|
+
#### Formatting
|
149
147
|
|
150
148
|
By default, FriendlyId uses Active Support's
|
151
|
-
paramaterize
|
149
|
+
[paramaterize](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize)
|
152
150
|
method to create slugs. This method will intelligently replace spaces with
|
153
151
|
dashes, and Unicode Latin characters with ASCII approximations:
|
154
152
|
|
155
|
-
|
156
|
-
|
153
|
+
movie = Movie.create! :title => "Der Preis fürs Überleben"
|
154
|
+
movie.slug #=> "der-preis-furs-uberleben"
|
157
155
|
|
158
|
-
|
156
|
+
#### Column or Method?
|
159
157
|
|
160
|
-
|
161
|
-
|
158
|
+
FriendlyId always uses a method as the basis of the slug text - not a column. It
|
159
|
+
first glance, this may sound confusing, but remember that Active Record provides
|
160
|
+
methods for each column in a model's associated table, and that's what
|
161
|
+
FriendlyId uses.
|
162
162
|
|
163
|
-
|
164
|
-
car2 = Car.create :title => "Peugot 206"
|
163
|
+
Here's an example of a class that uses a custom method to generate the slug:
|
165
164
|
|
166
|
-
|
167
|
-
|
165
|
+
class Person < ActiveRecord::Base
|
166
|
+
friendly_id :name_and_location
|
167
|
+
def name_and_location
|
168
|
+
"#{name} from #{location}"
|
169
|
+
end
|
170
|
+
end
|
168
171
|
|
169
|
-
|
172
|
+
bob = Person.create! :name => "Bob Smith", :location => "New York City"
|
173
|
+
bob.friendly_id #=> "bob-smith-from-new-york-city"
|
170
174
|
|
171
|
-
|
175
|
+
FriendlyId refers to this internally as the "base" method.
|
172
176
|
|
173
|
-
|
174
|
-
sequence_separator} configuration option.
|
177
|
+
#### Uniqueness
|
175
178
|
|
176
|
-
|
179
|
+
When you try to insert a record that would generate a duplicate friendly id,
|
180
|
+
FriendlyId will append a UUID to the generated slug to ensure uniqueness:
|
177
181
|
|
178
|
-
|
179
|
-
|
180
|
-
methods for each column in a model's associated table, and that's what
|
181
|
-
FriendlyId uses.
|
182
|
+
car = Car.create :title => "Peugot 206"
|
183
|
+
car2 = Car.create :title => "Peugot 206"
|
182
184
|
|
183
|
-
|
185
|
+
car.friendly_id #=> "peugot-206"
|
186
|
+
car2.friendly_id #=> "peugot-206-f9f3789a-daec-4156-af1d-fab81aa16ee5"
|
184
187
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
188
|
+
Previous versions of FriendlyId appended a numeric sequence a to make slugs
|
189
|
+
unique, but this was removed to simplify using FriendlyId in concurrent code.
|
190
|
+
|
191
|
+
#### Candidates
|
192
|
+
|
193
|
+
Since UUIDs are ugly, FriendlyId provides a "slug candidates" functionality to
|
194
|
+
let you specify alternate slugs to use in the event the one you want to use is
|
195
|
+
already taken. For example:
|
196
|
+
|
197
|
+
class Restaurant < ActiveRecord::Base
|
198
|
+
extend FriendlyId
|
199
|
+
friendly_id :slug_candidates, use: :slugged
|
200
|
+
|
201
|
+
# Try building a slug based on the following fields in
|
202
|
+
# increasing order of specificity.
|
203
|
+
def slug_candidates
|
204
|
+
[
|
205
|
+
:name,
|
206
|
+
[:name, :city],
|
207
|
+
[:name, :street, :city],
|
208
|
+
[:name, :street_number, :street, :city]
|
209
|
+
]
|
210
|
+
end
|
189
211
|
end
|
190
|
-
end
|
191
212
|
|
192
|
-
|
193
|
-
|
213
|
+
r1 = Restaurant.create! name: 'Plaza Diner', city: 'New Paltz'
|
214
|
+
r2 = Restaurant.create! name: 'Plaza Diner', city: 'Kingston'
|
194
215
|
|
195
|
-
|
216
|
+
r1.friendly_id #=> 'plaza-diner'
|
217
|
+
r2.friendly_id #=> 'plaza-diner-kingston'
|
196
218
|
|
197
|
-
|
198
|
-
|
219
|
+
To use candidates, make your FriendlyId base method return an array. The
|
220
|
+
method need not be named `slug_candidates`; it can be anything you want. The
|
221
|
+
array may contain any combination of symbols, strings, procs or lambdas and
|
222
|
+
will be evaluated lazily and in order. If you include symbols, FriendlyId will
|
223
|
+
invoke a method on your model class with the same name. Strings will be
|
224
|
+
interpreted literally. Procs and lambdas will be called and their return values
|
225
|
+
used as the basis of the friendly id. If none of the candidates can generate a
|
226
|
+
unique slug, then FriendlyId will append a UUID to the first candidate as a
|
227
|
+
last resort.
|
199
228
|
|
200
|
-
|
229
|
+
#### Sequence Separator
|
201
230
|
|
202
|
-
|
203
|
-
control whether new friendly ids are created when a model is updated. For
|
204
|
-
example, if you only want to generate slugs once and then treat them as
|
205
|
-
read-only:
|
231
|
+
By default, FriendlyId uses a dash to separate the slug from a sequence.
|
206
232
|
|
207
|
-
|
208
|
-
|
209
|
-
friendly_id :title, :use => :slugged
|
233
|
+
You can change this with the {FriendlyId::Slugged::Configuration#sequence_separator
|
234
|
+
sequence_separator} configuration option.
|
210
235
|
|
211
|
-
|
212
|
-
new_record?
|
213
|
-
end
|
214
|
-
end
|
236
|
+
#### Providing Your Own Slug Processing Method
|
215
237
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
post.save!
|
220
|
-
post.slug #=> "hello-world"
|
238
|
+
You can override {FriendlyId::Slugged#normalize_friendly_id} in your model for
|
239
|
+
total control over the slug format. It will be invoked for any generated slug,
|
240
|
+
whether for a single slug or for slug candidates.
|
221
241
|
|
222
|
-
|
242
|
+
#### Deciding When to Generate New Slugs
|
223
243
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
locale when replacing Latin characters:
|
244
|
+
Previous versions of FriendlyId provided a method named
|
245
|
+
`should_generate_new_friendly_id?` which you could override to control when new
|
246
|
+
slugs were generated.
|
228
247
|
|
229
|
-
|
230
|
-
|
231
|
-
i18n:
|
232
|
-
transliterate:
|
233
|
-
rule:
|
234
|
-
ü: "ue"
|
235
|
-
ö: "oe"
|
236
|
-
etc...
|
248
|
+
As of FriendlyId 5.0, slugs are only generated when the `slug` field is nil. If
|
249
|
+
you want a slug to be regenerated, you must explicity set the field to nil:
|
237
250
|
|
238
|
-
|
239
|
-
|
251
|
+
restaurant.friendly_id # joes-diner
|
252
|
+
restaurant.name = "The Plaza Diner"
|
253
|
+
restaurant.save!
|
254
|
+
restaurant.friendly_id # joes-diner
|
255
|
+
restaurant.slug = nil
|
256
|
+
restaurant.save!
|
257
|
+
restaurant.friendly_id # the-plaza-diner
|
240
258
|
|
241
|
-
This functionality was in fact taken from earlier versions of FriendlyId.
|
242
259
|
|
243
|
-
|
260
|
+
#### Locale-specific Transliterations
|
244
261
|
|
245
|
-
|
262
|
+
Active Support's `parameterize` uses
|
263
|
+
[transliterate](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate),
|
264
|
+
which in turn can use I18n's transliteration rules to consider the current
|
265
|
+
locale when replacing Latin characters:
|
246
266
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
267
|
+
# config/locales/de.yml
|
268
|
+
de:
|
269
|
+
i18n:
|
270
|
+
transliterate:
|
271
|
+
rule:
|
272
|
+
ü: "ue"
|
273
|
+
ö: "oe"
|
274
|
+
etc...
|
251
275
|
|
252
|
-
|
276
|
+
movie = Movie.create! :title => "Der Preis fürs Überleben"
|
277
|
+
movie.slug #=> "der-preis-fuers-ueberleben"
|
253
278
|
|
254
|
-
|
255
|
-
* Use explicit finders like +find_by_id+ to always find by the numeric id, or
|
256
|
-
+find_by_slug+ to always find using the friendly id.
|
279
|
+
This functionality was in fact taken from earlier versions of FriendlyId.
|
257
280
|
|
258
|
-
|
281
|
+
#### Gotchas: Common Problems
|
259
282
|
|
260
283
|
FriendlyId uses a before_validation callback to generate and set the slug. This
|
261
284
|
means that if you create two model instances before saving them, it's possible
|
@@ -266,15 +289,11 @@ attributes creates more than one record for a model that uses friendly_id. The
|
|
266
289
|
second, in concurrent code, either in threads or multiple processes.
|
267
290
|
|
268
291
|
To solve the nested attributes issue, I recommend simply avoiding them when
|
269
|
-
creating more than one nested record for a model that uses FriendlyId. See
|
270
|
-
Github issue
|
271
|
-
|
272
|
-
To solve the concurrency issue, I recommend locking the model's table against
|
273
|
-
inserts while when saving the record. See {this Github
|
274
|
-
issue}[https://github.com/FriendlyId/friendly_id/issues/180] for discussion.
|
292
|
+
creating more than one nested record for a model that uses FriendlyId. See [this
|
293
|
+
Github issue](https://github.com/norman/friendly_id/issues/185) for discussion.
|
275
294
|
|
276
295
|
|
277
|
-
|
296
|
+
## History: Avoiding 404's When Slugs Change
|
278
297
|
|
279
298
|
FriendlyId's {FriendlyId::History History} module adds the ability to store a
|
280
299
|
log of a model's slugs, so that when its friendly id changes, it's still
|
@@ -282,26 +301,24 @@ possible to perform finds by the old id.
|
|
282
301
|
|
283
302
|
The primary use case for this is avoiding broken URLs.
|
284
303
|
|
285
|
-
|
304
|
+
### Setup
|
286
305
|
|
287
306
|
In order to use this module, you must add a table to your database schema to
|
288
307
|
store the slug records. FriendlyId provides a generator for this purpose:
|
289
308
|
|
290
|
-
|
291
|
-
|
309
|
+
rails generate friendly_id
|
310
|
+
rake db:migrate
|
292
311
|
|
293
|
-
This will add a table named
|
312
|
+
This will add a table named `friendly_id_slugs`, used by the {FriendlyId::Slug}
|
294
313
|
model.
|
295
314
|
|
296
|
-
|
297
|
-
|
298
|
-
This module is incompatible with the +:scoped+ module.
|
315
|
+
### Considerations
|
299
316
|
|
300
317
|
Because recording slug history requires creating additional database records,
|
301
|
-
this module has an impact on the performance of the associated model's
|
318
|
+
this module has an impact on the performance of the associated model's `create`
|
302
319
|
method.
|
303
320
|
|
304
|
-
|
321
|
+
### Example
|
305
322
|
|
306
323
|
class Post < ActiveRecord::Base
|
307
324
|
extend FriendlyId
|
@@ -327,13 +344,13 @@ method.
|
|
327
344
|
end
|
328
345
|
|
329
346
|
|
330
|
-
|
347
|
+
## Unique Slugs by Scope
|
331
348
|
|
332
349
|
The {FriendlyId::Scoped} module allows FriendlyId to generate unique slugs
|
333
350
|
within a scope.
|
334
351
|
|
335
352
|
This allows, for example, two restaurants in different cities to have the slug
|
336
|
-
|
353
|
+
`joes-diner`:
|
337
354
|
|
338
355
|
class Restaurant < ActiveRecord::Base
|
339
356
|
extend FriendlyId
|
@@ -347,16 +364,16 @@ This allows, for example, two restaurants in different cities to have the slug
|
|
347
364
|
friendly_id :name, :use => :slugged
|
348
365
|
end
|
349
366
|
|
350
|
-
City.find("seattle").restaurants.find("joes-diner")
|
351
|
-
City.find("chicago").restaurants.find("joes-diner")
|
367
|
+
City.friendly.find("seattle").restaurants.friendly.find("joes-diner")
|
368
|
+
City.friendly.find("chicago").restaurants.friendly.find("joes-diner")
|
352
369
|
|
353
370
|
Without :scoped in this case, one of the restaurants would have the slug
|
354
|
-
|
371
|
+
`joes-diner` and the other would have `joes-diner-f9f3789a-daec-4156-af1d-fab81aa16ee5`.
|
355
372
|
|
356
|
-
The value for the
|
373
|
+
The value for the `:scope` option can be the name of a `belongs_to` relation, or
|
357
374
|
a column.
|
358
375
|
|
359
|
-
Additionally, the
|
376
|
+
Additionally, the `:scope` option can receive an array of scope values:
|
360
377
|
|
361
378
|
class Cuisine < ActiveRecord::Base
|
362
379
|
extend FriendlyId
|
@@ -378,30 +395,30 @@ Additionally, the +:scope+ option can receive an array of scope values:
|
|
378
395
|
|
379
396
|
All supplied values will be used to determine scope.
|
380
397
|
|
381
|
-
|
398
|
+
### Finding Records by Friendly ID
|
382
399
|
|
383
400
|
If you are using scopes your friendly ids may not be unique, so a simple find
|
384
401
|
like
|
385
402
|
|
386
|
-
Restaurant.find("joes-diner")
|
403
|
+
Restaurant.friendly.find("joes-diner")
|
387
404
|
|
388
405
|
may return the wrong record. In these cases it's best to query through the
|
389
406
|
relation:
|
390
407
|
|
391
|
-
@city.restaurants.find("joes-diner")
|
408
|
+
@city.restaurants.friendly.find("joes-diner")
|
392
409
|
|
393
410
|
Alternatively, you could pass the scope value as a query parameter:
|
394
411
|
|
395
|
-
Restaurant.find("joes-diner").where(:city_id => @city.id)
|
412
|
+
Restaurant.friendly.find("joes-diner").where(:city_id => @city.id)
|
396
413
|
|
397
414
|
|
398
|
-
|
415
|
+
### Finding All Records That Match a Scoped ID
|
399
416
|
|
400
417
|
Query the slug column directly:
|
401
418
|
|
402
|
-
Restaurant.
|
419
|
+
Restaurant.where(:slug => "joes-diner")
|
403
420
|
|
404
|
-
|
421
|
+
### Routes for Scoped Models
|
405
422
|
|
406
423
|
Recall that FriendlyId is a database-centric library, and does not set up any
|
407
424
|
routes for scoped models. You must do this yourself in your application. Here's
|
@@ -416,15 +433,15 @@ an example of one way to set this up:
|
|
416
433
|
<%= link_to 'Show', [@city, @restaurant] %>
|
417
434
|
|
418
435
|
# in controllers
|
419
|
-
@city = City.find(params[:city_id])
|
420
|
-
@restaurant = @city.restaurants.find(params[:id])
|
436
|
+
@city = City.friendly.find(params[:city_id])
|
437
|
+
@restaurant = @city.restaurants.friendly.find(params[:id])
|
421
438
|
|
422
439
|
# URLs:
|
423
440
|
http://example.org/cities/seattle/restaurants/joes-diner
|
424
441
|
http://example.org/cities/chicago/restaurants/joes-diner
|
425
442
|
|
426
443
|
|
427
|
-
|
444
|
+
## Translating Slugs Using Simple I18n
|
428
445
|
|
429
446
|
The {FriendlyId::SimpleI18n SimpleI18n} module adds very basic i18n support to
|
430
447
|
FriendlyId.
|
@@ -432,64 +449,64 @@ FriendlyId.
|
|
432
449
|
In order to use this module, your model must have a slug column for each locale.
|
433
450
|
By default FriendlyId looks for columns named, for example, "slug_en",
|
434
451
|
"slug_es", etc. The first part of the name can be configured by passing the
|
435
|
-
|
452
|
+
`:slug_column` option if you choose. Note that the column for the default locale
|
436
453
|
must also include the locale in its name.
|
437
454
|
|
438
455
|
This module is most suitable to applications that need to support few locales.
|
439
456
|
If you need to support two or more locales, you may wish to use the
|
440
457
|
friendly_id_globalize gem instead.
|
441
458
|
|
442
|
-
|
459
|
+
### Example migration
|
443
460
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
461
|
+
def self.up
|
462
|
+
create_table :posts do |t|
|
463
|
+
t.string :title
|
464
|
+
t.string :slug_en
|
465
|
+
t.string :slug_es
|
466
|
+
t.text :body
|
467
|
+
end
|
468
|
+
add_index :posts, :slug_en
|
469
|
+
add_index :posts, :slug_es
|
450
470
|
end
|
451
|
-
add_index :posts, :slug_en
|
452
|
-
add_index :posts, :slug_es
|
453
|
-
end
|
454
471
|
|
455
|
-
|
472
|
+
### Finds
|
456
473
|
|
457
474
|
Finds will take into consideration the current locale:
|
458
475
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
476
|
+
I18n.locale = :es
|
477
|
+
Post.find("la-guerra-de-las-galaxas")
|
478
|
+
I18n.locale = :en
|
479
|
+
Post.find("star-wars")
|
463
480
|
|
464
481
|
To find a slug by an explicit locale, perform the find inside a block
|
465
|
-
passed to I18n's
|
482
|
+
passed to I18n's `with_locale` method:
|
466
483
|
|
467
|
-
|
468
|
-
|
469
|
-
|
484
|
+
I18n.with_locale(:es) do
|
485
|
+
Post.find("la-guerra-de-las-galaxas")
|
486
|
+
end
|
470
487
|
|
471
|
-
|
488
|
+
### Creating Records
|
472
489
|
|
473
490
|
When new records are created, the slug is generated for the current locale only.
|
474
491
|
|
475
|
-
|
492
|
+
### Translating Slugs
|
476
493
|
|
477
494
|
To translate an existing record's friendly_id, use
|
478
495
|
{FriendlyId::SimpleI18n::Model#set_friendly_id}. This will ensure that the slug
|
479
496
|
you add is properly escaped, transliterated and sequenced:
|
480
497
|
|
481
|
-
|
482
|
-
|
498
|
+
post = Post.create :name => "Star Wars"
|
499
|
+
post.set_friendly_id("La guerra de las galaxas", :es)
|
483
500
|
|
484
501
|
If you don't pass in a locale argument, FriendlyId::SimpleI18n will just use the
|
485
502
|
current locale:
|
486
503
|
|
487
|
-
|
488
|
-
|
489
|
-
|
504
|
+
I18n.with_locale(:es) do
|
505
|
+
post.set_friendly_id("La guerra de las galaxas")
|
506
|
+
end
|
490
507
|
|
491
508
|
|
492
|
-
|
509
|
+
## Reserved Words
|
493
510
|
|
494
511
|
The {FriendlyId::Reserved Reserved} module adds the ability to exlude a list of
|
495
512
|
words from use as FriendlyId slugs.
|
@@ -504,7 +521,7 @@ FriendlyId.defaults}:
|
|
504
521
|
config.reserved_words = %w(new edit nueva nuevo editar)
|
505
522
|
end
|
506
523
|
|
507
|
-
Note that the error message will appear on the field
|
524
|
+
Note that the error message will appear on the field `:friendly_id`. If you are
|
508
525
|
using Rails's scaffolded form errors display, then it will have no field to
|
509
526
|
highlight. If you'd like to change this so that scaffolding works as expected,
|
510
527
|
one way to accomplish this is to move the error message to a different field.
|