mil_friendly_id 4.0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +12 -0
  4. data/.travis.yml +20 -0
  5. data/.yardopts +4 -0
  6. data/Changelog.md +86 -0
  7. data/Gemfile +15 -0
  8. data/Guide.rdoc +553 -0
  9. data/MIT-LICENSE +19 -0
  10. data/README.md +150 -0
  11. data/Rakefile +108 -0
  12. data/WhatsNew.md +95 -0
  13. data/bench.rb +63 -0
  14. data/friendly_id.gemspec +43 -0
  15. data/gemfiles/Gemfile.rails-3.0.rb +21 -0
  16. data/gemfiles/Gemfile.rails-3.1.rb +22 -0
  17. data/gemfiles/Gemfile.rails-3.2.rb +22 -0
  18. data/geothird_friendly_id.gemspec +45 -0
  19. data/lib/friendly_id.rb +114 -0
  20. data/lib/friendly_id/base.rb +291 -0
  21. data/lib/friendly_id/configuration.rb +80 -0
  22. data/lib/friendly_id/finder_methods.rb +35 -0
  23. data/lib/friendly_id/globalize.rb +115 -0
  24. data/lib/friendly_id/history.rb +134 -0
  25. data/lib/friendly_id/migration.rb +19 -0
  26. data/lib/friendly_id/object_utils.rb +50 -0
  27. data/lib/friendly_id/reserved.rb +68 -0
  28. data/lib/friendly_id/scoped.rb +149 -0
  29. data/lib/friendly_id/simple_i18n.rb +95 -0
  30. data/lib/friendly_id/slug.rb +14 -0
  31. data/lib/friendly_id/slug_generator.rb +80 -0
  32. data/lib/friendly_id/slugged.rb +329 -0
  33. data/lib/generators/friendly_id_generator.rb +17 -0
  34. data/mil_friendly_id.gemspec +45 -0
  35. data/test/base_test.rb +72 -0
  36. data/test/compatibility/ancestry/Gemfile +8 -0
  37. data/test/compatibility/ancestry/ancestry_test.rb +34 -0
  38. data/test/compatibility/threading/Gemfile +8 -0
  39. data/test/compatibility/threading/threading.rb +45 -0
  40. data/test/configuration_test.rb +48 -0
  41. data/test/core_test.rb +48 -0
  42. data/test/databases.yml +19 -0
  43. data/test/generator_test.rb +20 -0
  44. data/test/globalize_test.rb +57 -0
  45. data/test/helper.rb +87 -0
  46. data/test/history_test.rb +149 -0
  47. data/test/object_utils_test.rb +28 -0
  48. data/test/reserved_test.rb +40 -0
  49. data/test/schema.rb +79 -0
  50. data/test/scoped_test.rb +83 -0
  51. data/test/shared.rb +156 -0
  52. data/test/simple_i18n_test.rb +133 -0
  53. data/test/slugged_test.rb +280 -0
  54. data/test/sti_test.rb +77 -0
  55. metadata +262 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c6e5e405a8f499b763823ebfd2f64d3328b04770
4
+ data.tar.gz: f1af5d445ae42d992a9bb329d477affa920eaedb
5
+ SHA512:
6
+ metadata.gz: bafb0972a9545b7d49dd3b20577ef0568b969cf1b3acb886f61bc66e934729bf1e6dcb61bf902fd39903e581f7014dea0696607c822dbb82d738e1d752d8695b
7
+ data.tar.gz: fcc3ed19d1a22963c4175b814fa91dad9f5ababe94c7c4c0ffe9f9dcf5f13a92f8bce6e91522f3bf74ec4a36c929c814c1b2c250162bcbf293b6ed9acbf4dbf0
File without changes
@@ -0,0 +1,12 @@
1
+ Gemfile.lock
2
+ doc
3
+ docs
4
+ pkg
5
+ .DS_Store
6
+ coverage
7
+ .yardoc
8
+ *.gem
9
+ *.sqlite3
10
+ *.rbc
11
+ *.lock
12
+ .rbx
@@ -0,0 +1,20 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 1.8.7
4
+ # - jruby
5
+ # - rbx
6
+
7
+ branches:
8
+ only:
9
+ - master
10
+ env:
11
+ - DB=postgres
12
+ - DB=mysql
13
+ - DB=sqlite3
14
+
15
+ gemfile:
16
+ - gemfiles/Gemfile.rails-3.0.rb
17
+ - gemfiles/Gemfile.rails-3.1.rb
18
+ - gemfiles/Gemfile.rails-3.2.rb
19
+ before_script: 'bundle exec rake db:create db:up > /dev/null'
20
+ script: 'bundle exec rake test'
@@ -0,0 +1,4 @@
1
+ --files=WhatsNew.md,Changelog.md,Guide.rdoc
2
+ --private
3
+ --protected
4
+ --exclude lib/friendly_id/migration
@@ -0,0 +1,86 @@
1
+ # FriendlyId Changelog
2
+
3
+ We would like to think our many {file:Contributors contributors} for
4
+ suggestions, ideas and improvements to FriendlyId.
5
+
6
+ * Table of Contents
7
+ {:toc}
8
+
9
+ ## 4.0.9 (2012-10-31)
10
+
11
+ * Fixed support for Rails 3.2.9.rc1
12
+
13
+ ## 4.0.8 (2012-08-01)
14
+
15
+ * Name internal anonymous class to fix marshall dump/load error (Jess Brown, Philip Arndt and Norman Clarke).
16
+
17
+ * Avoid using deprecated `update_attribute` (Philip Arndt).
18
+
19
+ * Added set_friendly_id method to Globalize module (Norman Clarke).
20
+
21
+ * autoload FriendlyId::Slug; previously this class was not accessible from
22
+ migrations unless required explicitly, which could cause some queries to
23
+ unexpectedly fail (Norman Clarke).
24
+
25
+ * Fix Mocha load order (Mark Turner).
26
+
27
+ * Minor doc updates (Rob Yurkowski).
28
+
29
+ * Other miscellaneous refactorings and doc updates.
30
+
31
+ ## 4.0.7 (2012-06-06)
32
+
33
+ * to_param just calls super when no friendly_id is present, to keep the model's
34
+ default behavior. (Andrew White)
35
+
36
+ * FriendlyId can now properly sequence slugs that end in numbers even when a
37
+ single dash is used as the separator (Tomás Arribas).
38
+
39
+ ## 4.0.6 (2012-05-21)
40
+
41
+ * Fix nil return value from to_param when save fails because of validation errors (Tomás Arribas)
42
+ * Fix incorrect usage of i18n API (Vinicius Ferriani)
43
+ * Improve error handling in reserved module (Adrián Mugnolo and Github user "nolamesa")
44
+
45
+ ## 4.0.5 (2012-04-28)
46
+
47
+ * Favor `includes` over `joins` in globalize to avoid read-only results (Jakub Wojtysiak)
48
+ * Fix globalize compatibility with results from dynamic finders (Chris Salzberg)
49
+
50
+
51
+ ## 4.0.4 (2012-03-26)
52
+
53
+ * Fix globalize plugin to avoid issues with asset precompilation (Philip Arndt)
54
+
55
+
56
+ ## 4.0.3 (2012-03-14)
57
+
58
+ * Fix escape for '%' and '_' on SQLite (Norman Clarke and Sergey Petrunin)
59
+ * Allow FriendlyId to be extended or included (Norman Clarke)
60
+ * Allow Configuration#use to accept a Module (Norman Clarke)
61
+ * Fix bugs with History module + STI (Norman Clarke and Sergey Petrunin)
62
+
63
+ ## 4.0.2 (2012-03-12)
64
+
65
+ * Improved conflict handling and performance in History module (Erik Ogan and Thomas Shafer)
66
+ * Fixed bug that impeded using underscores as a sequence separator (Erik Ogan and Thomas Shafer)
67
+ * Minor documentation improvements (Norman Clarke)
68
+
69
+ ## 4.0.1 (2012-02-29)
70
+
71
+ * Added support for Globalize 3 (Enrico Pilotto and Philip Arndt)
72
+ * Allow the scoped module to use multiple scopes (Ben Caldwell)
73
+ * Fixes for conflicting slugs in history module (Erik Ogan, Thomas Shafer, Evan Arnold)
74
+ * Fix for conflicting slugs when using STI (Danny van der Heiden, Diederick Lawson)
75
+ * Maintainence improvements (Norman Clarke, Philip Arndt, Thomas Darde, Lee Hambley)
76
+
77
+ ## 4.0.0 (2011-12-27)
78
+
79
+ This is a complete rewrite of FriendlyId, and introduces a smaller, faster and
80
+ less ambitious codebase. The primary change is the relegation of external slugs
81
+ to an optional addon, and the adoption of what were formerly "cached slugs"
82
+ as the primary way of handling slugging.
83
+
84
+ ## Older releases
85
+
86
+ Please see the 3.x branch.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ # Database Configuration
6
+ group :development, :test do
7
+ platforms :jruby do
8
+ gem 'activerecord-jdbcsqlite3-adapter'
9
+ gem 'jruby-openssl'
10
+ end
11
+
12
+ platforms :ruby do
13
+ gem 'sqlite3'
14
+ end
15
+ end
@@ -0,0 +1,553 @@
1
+ #encoding: utf-8
2
+
3
+
4
+ == About FriendlyId
5
+
6
+ FriendlyId is an add-on to Ruby's Active Record that allows you to replace ids
7
+ in your URLs with strings:
8
+
9
+ # without FriendlyId
10
+ http://example.com/states/4323454
11
+
12
+ # with FriendlyId
13
+ http://example.com/states/washington
14
+
15
+ It requires few changes to your application code and offers flexibility,
16
+ performance and a well-documented codebase.
17
+
18
+ === Core Concepts
19
+
20
+ ==== Slugs
21
+
22
+ The concept of "slugs[http://en.wikipedia.org/wiki/Slug_(web_publishing)]" is at
23
+ the heart of FriendlyId.
24
+
25
+ A slug is the part of a URL which identifies a page using human-readable
26
+ keywords, rather than an opaque identifier such as a numeric id. This can make
27
+ your application more friendly both for users and search engine.
28
+
29
+ ==== Finders: Slugs Act Like Numeric IDs
30
+
31
+ To the extent possible, FriendlyId lets you treat text-based identifiers like
32
+ normal IDs. This means that you can perform finds with slugs just like you do
33
+ with numeric ids:
34
+
35
+ Person.find(82542335)
36
+ Person.find("joe")
37
+
38
+
39
+ == Setting Up FriendlyId in Your Model
40
+
41
+ To use FriendlyId in your ActiveRecord models, you must first either extend or
42
+ include the FriendlyId module (it makes no difference), then invoke the
43
+ {FriendlyId::Base#friendly_id friendly_id} method to configure your desired
44
+ options:
45
+
46
+ class Foo < ActiveRecord::Base
47
+ include FriendlyId
48
+ friendly_id :bar, :use => [:slugged, :simple_i18n]
49
+ end
50
+
51
+ The most important option is `:use`, which you use to tell FriendlyId which
52
+ addons it should use. See the documentation for this method for a list of all
53
+ available addons, or skim through the rest of the docs to get a high-level
54
+ overview.
55
+
56
+ === The Default Setup: Simple Models
57
+
58
+ The simplest way to use FriendlyId is with a model that has a uniquely indexed
59
+ column with no spaces or special characters, and that is seldom or never
60
+ updated. The most common example of this is a user name:
61
+
62
+ class User < ActiveRecord::Base
63
+ extend FriendlyId
64
+ friendly_id :login
65
+ validates_format_of :login, :with => /\A[a-z0-9]+\z/i
66
+ end
67
+
68
+ @user = User.find "joe" # the old User.find(1) still works, too
69
+ @user.to_param # returns "joe"
70
+ redirect_to @user # the URL will be /users/joe
71
+
72
+ In this case, FriendlyId assumes you want to use the column as-is; it will never
73
+ modify the value of the column, and your application should ensure that the
74
+ value is unique and admissible in a URL:
75
+
76
+ class City < ActiveRecord::Base
77
+ extend FriendlyId
78
+ friendly_id :name
79
+ end
80
+
81
+ @city.find "Viña del Mar"
82
+ redirect_to @city # the URL will be /cities/Viña%20del%20Mar
83
+
84
+ Writing the code to process an arbitrary string into a good identifier for use
85
+ in a URL can be repetitive and surprisingly tricky, so for this reason it's
86
+ often better and easier to use {FriendlyId::Slugged slugs}.
87
+
88
+
89
+ == Slugged Models
90
+
91
+ FriendlyId can use a separate column to store slugs for models which require
92
+ some text processing.
93
+
94
+ For example, blog applications typically use a post title to provide the basis
95
+ of a search engine friendly URL. Such identifiers typically lack uppercase
96
+ characters, use ASCII to approximate UTF-8 character, and strip out other
97
+ characters which may make them aesthetically unappealing or error-prone when
98
+ used in a URL.
99
+
100
+ class Post < ActiveRecord::Base
101
+ extend FriendlyId
102
+ friendly_id :title, :use => :slugged
103
+ end
104
+
105
+ @post = Post.create(:title => "This is the first post!")
106
+ @post.friendly_id # returns "this-is-the-first-post"
107
+ redirect_to @post # the URL will be /posts/this-is-the-first-post
108
+
109
+ In general, use slugs by default unless you know for sure you don't need them.
110
+ To activate the slugging functionality, use the {FriendlyId::Slugged} module.
111
+
112
+ FriendlyId will generate slugs from a method or column that you specify, and
113
+ store them in a field in your model. By default, this field must be named
114
+ +:slug+, though you may change this using the
115
+ {FriendlyId::Slugged::Configuration#slug_column slug_column} configuration
116
+ option. You should add an index to this column, and in most cases, make it
117
+ unique. Do not make the column unique in case you wish to scope the slug
118
+ (more on this later). You may also wish to constrain it to NOT NULL, but this
119
+ depends on your app's behavior and requirements.
120
+
121
+ === Example Setup
122
+
123
+ # your model
124
+ class Post < ActiveRecord::Base
125
+ extend FriendlyId
126
+ friendly_id :title, :use => :slugged
127
+ validates_presence_of :title, :slug, :body
128
+ end
129
+
130
+ # a migration
131
+ class CreatePosts < ActiveRecord::Migration
132
+ def self.up
133
+ create_table :posts do |t|
134
+ t.string :title, :null => false
135
+ t.string :slug, :null => false
136
+ t.text :body
137
+ end
138
+
139
+ add_index :posts, :slug, :unique => true
140
+ end
141
+
142
+ def self.down
143
+ drop_table :posts
144
+ end
145
+ end
146
+
147
+ === Working With Slugs
148
+
149
+ ==== Formatting
150
+
151
+ By default, FriendlyId uses Active Support's
152
+ paramaterize[http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize]
153
+ method to create slugs. This method will intelligently replace spaces with
154
+ dashes, and Unicode Latin characters with ASCII approximations:
155
+
156
+ movie = Movie.create! :title => "Der Preis fürs Überleben"
157
+ movie.slug #=> "der-preis-furs-uberleben"
158
+
159
+ ==== Uniqueness
160
+
161
+ When you try to insert a record that would generate a duplicate friendly id,
162
+ FriendlyId will append a sequence to the generated slug to ensure uniqueness:
163
+
164
+ car = Car.create :title => "Peugot 206"
165
+ car2 = Car.create :title => "Peugot 206"
166
+
167
+ car.friendly_id #=> "peugot-206"
168
+ car2.friendly_id #=> "peugot-206--2"
169
+
170
+ ==== Sequence Separator - The Two Dashes
171
+
172
+ By default, FriendlyId uses two dashes to separate the slug from a sequence.
173
+
174
+ You can change this with the {FriendlyId::Slugged::Configuration#sequence_separator
175
+ sequence_separator} configuration option.
176
+
177
+ ==== Column or Method?
178
+
179
+ FriendlyId always uses a method as the basis of the slug text - not a column. It
180
+ first glance, this may sound confusing, but remember that Active Record provides
181
+ methods for each column in a model's associated table, and that's what
182
+ FriendlyId uses.
183
+
184
+ Here's an example of a class that uses a custom method to generate the slug:
185
+
186
+ class Person < ActiveRecord::Base
187
+ friendly_id :name_and_location
188
+ def name_and_location
189
+ "#{name} from #{location}"
190
+ end
191
+ end
192
+
193
+ bob = Person.create! :name => "Bob Smith", :location => "New York City"
194
+ bob.friendly_id #=> "bob-smith-from-new-york-city"
195
+
196
+ ==== Providing Your Own Slug Processing Method
197
+
198
+ You can override {FriendlyId::Slugged#normalize_friendly_id} in your model for
199
+ total control over the slug format.
200
+
201
+ ==== Deciding When to Generate New Slugs
202
+
203
+ Overriding {FriendlyId::Slugged#should_generate_new_friendly_id?} lets you
204
+ control whether new friendly ids are created when a model is updated. For
205
+ example, if you only want to generate slugs once and then treat them as
206
+ read-only:
207
+
208
+ class Post < ActiveRecord::Base
209
+ extend FriendlyId
210
+ friendly_id :title, :use => :slugged
211
+
212
+ def should_generate_new_friendly_id?
213
+ new_record?
214
+ end
215
+ end
216
+
217
+ post = Post.create!(:title => "Hello world!")
218
+ post.slug #=> "hello-world"
219
+ post.title = "Hello there, world!"
220
+ post.save!
221
+ post.slug #=> "hello-world"
222
+
223
+ ==== Locale-specific Transliterations
224
+
225
+ Active Support's +parameterize+ uses
226
+ transliterate[http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate],
227
+ which in turn can use I18n's transliteration rules to consider the current
228
+ locale when replacing Latin characters:
229
+
230
+ # config/locales/de.yml
231
+ de:
232
+ i18n:
233
+ transliterate:
234
+ rule:
235
+ ü: "ue"
236
+ ö: "oe"
237
+ etc...
238
+
239
+ movie = Movie.create! :title => "Der Preis fürs Überleben"
240
+ movie.slug #=> "der-preis-fuers-ueberleben"
241
+
242
+ This functionality was in fact taken from earlier versions of FriendlyId.
243
+
244
+ ==== Gotchas: Common Problems
245
+
246
+ ===== Slugs That Begin With Numbers
247
+
248
+ Ruby's `to_i` function casts strings to integers in such a way that +23abc.to_i+
249
+ returns 23. Because FriendlyId falls back to finding by numeric id, this means
250
+ that if you attempt to find a record with a non-existant slug, and that slug
251
+ begins with a number, your find will probably return the wrong record.
252
+
253
+ There are two fairly simple ways to avoid this:
254
+
255
+ * Use validations to ensure that slugs don't begin with numbers.
256
+ * Use explicit finders like +find_by_id+ to always find by the numeric id, or
257
+ +find_by_slug+ to always find using the friendly id.
258
+
259
+ ===== Concurrency Issues
260
+
261
+ FriendlyId uses a before_validation callback to generate and set the slug. This
262
+ means that if you create two model instances before saving them, it's possible
263
+ they will generate the same slug, and the second save will fail.
264
+
265
+ This can happen in two fairly normal cases: the first, when a model using nested
266
+ attributes creates more than one record for a model that uses friendly_id. The
267
+ second, in concurrent code, either in threads or multiple processes.
268
+
269
+ To solve the nested attributes issue, I recommend simply avoiding them when
270
+ creating more than one nested record for a model that uses FriendlyId. See {this
271
+ Github issue}[https://github.com/norman/friendly_id/issues/185] for discussion.
272
+
273
+ To solve the concurrency issue, I recommend locking the model's table against
274
+ inserts while when saving the record. See {this Github
275
+ issue}[https://github.com/norman/friendly_id/issues/180] for discussion.
276
+
277
+
278
+ == History: Avoiding 404's When Slugs Change
279
+
280
+ FriendlyId's {FriendlyId::History History} module adds the ability to store a
281
+ log of a model's slugs, so that when its friendly id changes, it's still
282
+ possible to perform finds by the old id.
283
+
284
+ The primary use case for this is avoiding broken URLs.
285
+
286
+ === Setup
287
+
288
+ In order to use this module, you must add a table to your database schema to
289
+ store the slug records. FriendlyId provides a generator for this purpose:
290
+
291
+ rails generate friendly_id
292
+ rake db:migrate
293
+
294
+ This will add a table named +friendly_id_slugs+, used by the {FriendlyId::Slug}
295
+ model.
296
+
297
+ === Considerations
298
+
299
+ This module is incompatible with the +:scoped+ module.
300
+
301
+ Because recording slug history requires creating additional database records,
302
+ this module has an impact on the performance of the associated model's +create+
303
+ method.
304
+
305
+ === Example
306
+
307
+ class Post < ActiveRecord::Base
308
+ extend FriendlyId
309
+ friendly_id :title, :use => :history
310
+ end
311
+
312
+ class PostsController < ApplicationController
313
+
314
+ before_filter :find_post
315
+
316
+ ...
317
+
318
+ def find_post
319
+ @post = Post.find params[:id]
320
+
321
+ # If an old id or a numeric id was used to find the record, then
322
+ # the request path will not match the post_path, and we should do
323
+ # a 301 redirect that uses the current friendly id.
324
+ if request.path != post_path(@post)
325
+ return redirect_to @post, :status => :moved_permanently
326
+ end
327
+ end
328
+ end
329
+
330
+
331
+ == Unique Slugs by Scope
332
+
333
+ The {FriendlyId::Scoped} module allows FriendlyId to generate unique slugs
334
+ within a scope.
335
+
336
+ This allows, for example, two restaurants in different cities to have the slug
337
+ +joes-diner+:
338
+
339
+ class Restaurant < ActiveRecord::Base
340
+ extend FriendlyId
341
+ belongs_to :city
342
+ friendly_id :name, :use => :scoped, :scope => :city
343
+ end
344
+
345
+ class City < ActiveRecord::Base
346
+ extend FriendlyId
347
+ has_many :restaurants
348
+ friendly_id :name, :use => :slugged
349
+ end
350
+
351
+ City.find("seattle").restaurants.find("joes-diner")
352
+ City.find("chicago").restaurants.find("joes-diner")
353
+
354
+ Without :scoped in this case, one of the restaurants would have the slug
355
+ +joes-diner+ and the other would have +joes-diner--2+.
356
+
357
+ The value for the +:scope+ option can be the name of a +belongs_to+ relation, or
358
+ a column.
359
+
360
+ Please do note that you must drop the uniqueness constraint on the slug's
361
+ column in the database when you're scoping the slug.
362
+
363
+ === Finding Records by Friendly ID
364
+
365
+ If you are using scopes your friendly ids may not be unique, so a simple find
366
+ like
367
+
368
+ Restaurant.find("joes-diner")
369
+
370
+ may return the wrong record. In these cases it's best to query through the
371
+ relation:
372
+
373
+ @city.restaurants.find("joes-diner")
374
+
375
+ Alternatively, you could pass the scope value as a query parameter:
376
+
377
+ Restaurant.find("joes-diner").where(:city_id => @city.id)
378
+
379
+
380
+ === Finding All Records That Match a Scoped ID
381
+
382
+ Query the slug column directly:
383
+
384
+ Restaurant.find_all_by_slug("joes-diner")
385
+
386
+ === Routes for Scoped Models
387
+
388
+ Recall that FriendlyId is a database-centric library, and does not set up any
389
+ routes for scoped models. You must do this yourself in your application. Here's
390
+ an example of one way to set this up:
391
+
392
+ # in routes.rb
393
+ resources :cities do
394
+ resources :restaurants
395
+ end
396
+
397
+ # in views
398
+ <%= link_to 'Show', [@city, @restaurant] %>
399
+
400
+ # in controllers
401
+ @city = City.find(params[:city_id])
402
+ @restaurant = @city.restaurants.find(params[:id])
403
+
404
+ # URLs:
405
+ http://example.org/cities/seattle/restaurants/joes-diner
406
+ http://example.org/cities/chicago/restaurants/joes-diner
407
+
408
+
409
+ == Translating Slugs Using Simple I18n
410
+
411
+ The {FriendlyId::SimpleI18n SimpleI18n} module adds very basic i18n support to
412
+ FriendlyId.
413
+
414
+ In order to use this module, your model must have a slug column for each locale.
415
+ By default FriendlyId looks for columns named, for example, "slug_en",
416
+ "slug_es", etc. The first part of the name can be configured by passing the
417
+ +:slug_column+ option if you choose. Note that the column for the default locale
418
+ must also include the locale in its name.
419
+
420
+ This module is most suitable to applications that need to support few locales.
421
+ If you need to support two or more locales, you may wish to use the
422
+ {FriendlyId::Globalize Globalize} module instead.
423
+
424
+ === Example migration
425
+
426
+ def self.up
427
+ create_table :posts do |t|
428
+ t.string :title
429
+ t.string :slug_en
430
+ t.string :slug_es
431
+ t.text :body
432
+ end
433
+ add_index :posts, :slug_en
434
+ add_index :posts, :slug_es
435
+ end
436
+
437
+ === Finds
438
+
439
+ Finds will take into consideration the current locale:
440
+
441
+ I18n.locale = :es
442
+ Post.find("la-guerra-de-las-galaxas")
443
+ I18n.locale = :en
444
+ Post.find("star-wars")
445
+
446
+ To find a slug by an explicit locale, perform the find inside a block
447
+ passed to I18n's +with_locale+ method:
448
+
449
+ I18n.with_locale(:es) do
450
+ Post.find("la-guerra-de-las-galaxas")
451
+ end
452
+
453
+ === Creating Records
454
+
455
+ When new records are created, the slug is generated for the current locale only.
456
+
457
+ === Translating Slugs
458
+
459
+ To translate an existing record's friendly_id, use
460
+ {FriendlyId::SimpleI18n::Model#set_friendly_id}. This will ensure that the slug
461
+ you add is properly escaped, transliterated and sequenced:
462
+
463
+ post = Post.create :name => "Star Wars"
464
+ post.set_friendly_id("La guerra de las galaxas", :es)
465
+
466
+ If you don't pass in a locale argument, FriendlyId::SimpleI18n will just use the
467
+ current locale:
468
+
469
+ I18n.with_locale(:es) do
470
+ post.set_friendly_id("la-guerra-de-las-galaxas")
471
+ end
472
+
473
+
474
+ == Translating Slugs Using Globalize
475
+
476
+ The {FriendlyId::Globalize Globalize} module lets you use
477
+ Globalize[https://github.com/svenfuchs/globalize3] to translate slugs. This
478
+ module is most suitable for applications that need to be localized to many
479
+ languages. If your application only needs to be localized to one or two
480
+ languages, you may wish to consider the {FriendlyId::SimpleI18n SimpleI18n}
481
+ module.
482
+
483
+ In order to use this module, your model's table and translation table must both
484
+ have a slug column, and your model must set the +slug+ field as translatable
485
+ with Globalize:
486
+
487
+ class Post < ActiveRecord::Base
488
+ translates :title, :slug
489
+ extend FriendlyId
490
+ friendly_id :title, :use => :globalize
491
+ end
492
+
493
+ === Finds
494
+
495
+ Finds will take the current locale into consideration:
496
+
497
+ I18n.locale = :it
498
+ Post.find("guerre-stellari")
499
+ I18n.locale = :en
500
+ Post.find("star-wars")
501
+
502
+ To find a slug by an explicit locale, perform the find inside a block
503
+ passed to I18n's +with_locale+ method:
504
+
505
+ I18n.with_locale(:it) do
506
+ Post.find("guerre-stellari")
507
+ end
508
+
509
+ === Creating Records
510
+
511
+ When new records are created, the slug is generated for the current locale only.
512
+
513
+ === Translating Slugs
514
+
515
+ To translate an existing record's friendly_id, simply change the locale and
516
+ assign a value to the +slug+ field:
517
+
518
+ I18n.with_locale(:it) do
519
+ post.slug = "guerre-stellari"
520
+ end
521
+
522
+
523
+ == Reserved Words
524
+
525
+ The {FriendlyId::Reserved Reserved} module adds the ability to exlude a list of
526
+ words from use as FriendlyId slugs.
527
+
528
+ By default, FriendlyId reserves the words "new" and "edit" when this module is
529
+ included. You can configure this globally by using {FriendlyId.defaults
530
+ FriendlyId.defaults}:
531
+
532
+ FriendlyId.defaults do |config|
533
+ config.use :reserved
534
+ # Reserve words for English and Spanish URLs
535
+ config.reserved_words = %w(new edit nueva nuevo editar)
536
+ end
537
+
538
+ Note that the error message will appear on the field +:friendly_id+. If you are
539
+ using Rails's scaffolded form errors display, then it will have no field to
540
+ highlight. If you'd like to change this so that scaffolding works as expected,
541
+ one way to accomplish this is to move the error message to a different field.
542
+ For example:
543
+
544
+ class Person < ActiveRecord::Base
545
+ extend FriendlyId
546
+ friendly_id :name, use: :slugged
547
+
548
+ after_validation :move_friendly_id_error_to_name
549
+
550
+ def move_friendly_id_error_to_name
551
+ errors.messages[:name] = errors.messages.delete(:friendly_id)
552
+ end
553
+ end