mongoid-slug 7.0.0 → 7.1.0

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.
data/README.md CHANGED
@@ -1,392 +1,408 @@
1
- Mongoid Slug
2
- ============
3
-
4
- Mongoid Slug generates a URL slug or permalink based on one or more fields in a Mongoid model.
5
- It sits idly on top of [stringex](https://github.com/rsl/stringex), supporting non-Latin characters.
6
-
7
- [![Build Status](https://github.com/mongoid/mongoid-slug/actions/workflows/test.yml/badge.svg?query=branch%3Amaster)](https://github.com/mongoid/mongoid-slug/actions/workflows/test.ym?query=branch%3Amaster)
8
- [![Gem Version](https://badge.fury.io/rb/mongoid-slug.svg)](http://badge.fury.io/rb/mongoid-slug)
9
- [![Code Climate](https://codeclimate.com/github/mongoid/mongoid-slug.svg)](https://codeclimate.com/github/mongoid/mongoid-slug)
10
-
11
- ### Version Support
12
-
13
- Mongoid Slug 7.x requires at least Mongoid 7.0.0 and Ruby 2.7.0. For earlier Mongoid and Ruby version support, please use an earlier version of Mongoid Slug.
14
-
15
- Mongoid Slug is compatible with all MongoDB versions which Mongoid supports, however, please see "Slug Max Length" section below for MongoDB 4.0 and earlier.
16
-
17
- ### Installation
18
-
19
- Add to your Gemfile:
20
-
21
- ```ruby
22
- gem 'mongoid-slug'
23
- ```
24
-
25
- ### Usage
26
-
27
- ### Set Up a Slug
28
-
29
- ```ruby
30
- class Book
31
- include Mongoid::Document
32
- include Mongoid::Slug
33
-
34
- field :title
35
- slug :title
36
- end
37
- ```
38
-
39
- ### Find a Document by its Slug
40
-
41
- ```ruby
42
- # GET /books/a-thousand-plateaus
43
- book = Book.find params[:book_id]
44
- ```
45
-
46
- Mongoid Slug will attempt to determine whether you want to find using the `slugs` field or the `_id` field by inspecting the supplied parameters.
47
-
48
- * Mongoid Slug will perform a find based on `slugs` only if all arguments passed to `find` are of the type `String`.
49
- * If your document uses `BSON::ObjectId` identifiers, and all arguments look like valid `BSON::ObjectId`, then Mongoid Slug will perform a find based on `_id`.
50
- * If your document uses any other type of identifiers, and all arguments passed to `find` are of the same type, then Mongoid Slug will perform a find based on `_id`.
51
- * If your document uses `String` identifiers and you want to be able find by slugs or ids, to get the correct behaviour, you should add a `slug_id_strategy` option to your `_id` field definition. This option should return something that responds to `call` (a callable) and takes one string argument, e.g. a lambda. This callable must return true if the string looks like one of your ids.
52
-
53
- ```ruby
54
- Book.fields['_id'].type
55
- => String
56
-
57
- book = Book.find 'a-thousand-plateaus' # Finds by slugs
58
- => ...
59
-
60
- class Post
61
- include Mongoid::Document
62
- include Mongoid::Slug
63
-
64
- field :_id, type: String, slug_id_strategy: lambda { |id| id.start_with?('...') }
65
-
66
- field :name
67
- slug :name, history: true
68
- end
69
-
70
- Post.fields['_id'].type
71
- => String
72
-
73
- post = Post.find 'a-thousand-plateaus' # Finds by slugs
74
- => ...
75
-
76
- post = Post.find '50b1386a0482939864000001' # Finds by bson ids
77
- => ...
78
- ```
79
-
80
- [Examine slug.rb](lib/mongoid/slug.rb) for all available options.
81
-
82
- ### Updating Existing Records
83
-
84
- To set slugs for existing records run following rake task:
85
-
86
- ```ruby
87
- rake mongoid_slug:set
88
- ```
89
-
90
- You can pass model names as an option for which you want to set slugs:
91
-
92
- ```ruby
93
- rake mongoid_slug:set[Model1,Model2]
94
- ```
95
-
96
- ### Nil Slugs
97
-
98
- Empty slugs are possible and generate a `nil` value for the `_slugs` field. In the `Post` example above, a blank post `name` will cause the document record not to contain a `_slugs` field in the database. The default `_slugs` index is `sparse`, allowing that. If you wish to change this behavior add a custom `validates_presence_of :_slugs` validator to the document or change the database index to `sparse: false`.
99
-
100
- ### Custom Slug Generation
101
-
102
- By default Mongoid Slug generates slugs with stringex. If this is not desired you can define your own slug generator.
103
-
104
- There are two ways to define slug generator.
105
-
106
- #### Globally
107
-
108
- Configure a block in `config/initializers/mongoid_slug.rb` as follows:
109
-
110
- ```ruby
111
- Mongoid::Slug.configure do |c|
112
- # create a block that takes the current object as an argument and return the slug
113
- c.slug = proc { |cur_obj|
114
- cur_object.slug_builder.to_url
115
- }
116
- end
117
- ```
118
-
119
- #### On Model
120
-
121
- ```ruby
122
- class Caption
123
- include Mongoid::Document
124
- include Mongoid::Slug
125
-
126
- # create a block that takes the current object as an argument and returns the slug
127
- slug do |cur_object|
128
- cur_object.slug_builder.to_url
129
- end
130
- end
131
- ```
132
-
133
- The `to_url` method comes from [stringex](https://github.com/rsl/stringex).
134
-
135
- You can define a slug builder globally and/or override it per model.
136
-
137
- ### Indexing
138
-
139
- By default, Mongoid Slug will automatically generate an index for the slug, which will be created when you run `rake db:create_indexes`. This index will take into account scoping and other options described below.
140
-
141
- To skip this index generation, you may set `index: false` as follows:
142
-
143
- ```ruby
144
- class Employee
145
- include Mongoid::Document
146
- include Mongoid::Slug
147
-
148
- field :name
149
-
150
- slug :name, index: :false
151
- end
152
- ```
153
-
154
- ### Scoping
155
-
156
- To scope a slug by a reference association, pass `:scope`:
157
-
158
- ```ruby
159
- class Company
160
- include Mongoid::Document
161
-
162
- references_many :employees
163
- end
164
-
165
- class Employee
166
- include Mongoid::Document
167
- include Mongoid::Slug
168
-
169
- field :name
170
- referenced_in :company
171
-
172
- slug :name, scope: :company
173
- end
174
- ```
175
-
176
- In this example, if you create an employee without associating it with any company, the scope will fall back to the root employees collection.
177
-
178
- Currently, if you have an irregular association name, you **must** specify the `:inverse_of` option on the other side of the assocation.
179
-
180
- Embedded objects are automatically scoped by their parent.
181
-
182
- Note that the unique index on the `Employee` collection in this example is derived from the `scope` value and is `{ _slugs: 1, company_id: 1}`. Therefore `:company` must be `referenced_in` above the definition of `slug` or it will not be able to resolve the association and mistakenly create a `{ _slugs: 1, company: 1}` index. An alternative is to scope to the field itself as follows:
183
-
184
- ```ruby
185
- class Employee
186
- include Mongoid::Document
187
- include Mongoid::Slug
188
-
189
- field :name
190
- field :company_id
191
-
192
- slug :name, scope: :company_id
193
- end
194
- ```
195
-
196
- ### Slug Max Length
197
-
198
- MongoDB [featureCompatibilityVersion](https://docs.mongodb.com/manual/reference/command/setFeatureCompatibilityVersion/#std-label-view-fcv)
199
- "4.0" and earlier applies an [Index Key Limit](https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Index-Key-Limit)
200
- which limits the total size of an index entry to around 1KB and will raise error,
201
- `17280 - key too large to index` when trying to create a record that causes an index key to exceed that limit.
202
- By default slugs are of the form `text[-number]` and the text portion is limited in size
203
- to `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes.
204
- You can change this limit with `max_length` or set it to `nil` if you're running MongoDB
205
- with [failIndexKeyTooLong](https://docs.mongodb.org/manual/reference/parameters/#param.failIndexKeyTooLong) set to `false`.
206
-
207
- ```ruby
208
- class Company
209
- include Mongoid::Document
210
- include Mongoid::Slug
211
-
212
- field :name
213
-
214
- slug :name, max_length: 24
215
- end
216
- ```
217
-
218
- ### Optionally Find and Create Slugs per Model Type
219
-
220
- By default when using STI, the scope will be around the super-class.
221
-
222
- ```ruby
223
- class Book
224
- include Mongoid::Document
225
- include Mongoid::Slug
226
- field :title
227
-
228
- slug :title, history: true
229
- embeds_many :subjects
230
- has_many :authors
231
- end
232
-
233
- class ComicBook < Book
234
- end
235
-
236
- book = Book.create(title: 'Anti Oedipus')
237
- comic_book = ComicBook.create(title: 'Anti Oedipus')
238
- comic_book.slugs.should_not eql(book.slugs)
239
- ```
240
-
241
- If you want the scope to be around the subclass, then set the option `by_model_type: true`.
242
-
243
- ```ruby
244
- class Book
245
- include Mongoid::Document
246
- include Mongoid::Slug
247
- field :title
248
-
249
- slug :title, history: true, by_model_type: true
250
- embeds_many :subjects
251
- has_many :authors
252
- end
253
-
254
- class ComicBook < Book
255
- end
256
-
257
- book = Book.create(title: 'Anti Oedipus')
258
- comic_book = ComicBook.create(title: 'Anti Oedipus')
259
- comic_book.slugs.should eql(book.slugs)
260
- ```
261
-
262
- ### History
263
-
264
- Enable slug history tracking by setting `history: true`.
265
-
266
- ```ruby
267
- class Page
268
- include Mongoid::Document
269
- include Mongoid::Slug
270
-
271
- field :title
272
-
273
- slug :title, history: true
274
- end
275
- ```
276
-
277
- The document will then be returned for any of the saved slugs:
278
-
279
- ```ruby
280
- page = Page.new title: "Home"
281
- page.save
282
- page.update_attributes title: "Welcome"
283
-
284
- Page.find("welcome") == Page.find("home") # => true
285
- ```
286
-
287
- ### Reserved Slugs
288
-
289
- Pass words you do not want to be slugged using the `reserve` option:
290
-
291
- ```ruby
292
- class Friend
293
- include Mongoid::Document
294
-
295
- field :name
296
- slug :name, reserve: ['admin', 'root']
297
- end
298
-
299
- friend = Friend.create name: 'admin'
300
- Friend.find('admin') # => nil
301
- friend.slug # => 'admin-1'
302
- ```
303
-
304
- When reserved words are not specified, the words 'new' and 'edit' are considered reserved by default.
305
- Specifying an array of custom reserved words will overwrite these defaults.
306
-
307
- ### Localize Slugs
308
-
309
- The slugs can be localized. This feature is built upon Mongoid localized fields,
310
- so fallbacks and localization works as documented in the Mongoid manual.
311
-
312
- ```ruby
313
- class PageSlugLocalize
314
- include Mongoid::Document
315
- include Mongoid::Slug
316
-
317
- field :title, localize: true
318
- slug :title, localize: true
319
- end
320
- ```
321
-
322
- By specifying `localize: true`, the slug index will be created on the
323
- [I18n.default_locale](http://guides.rubyonrails.org/i18n.html#the-public-i18n-api) field only.
324
- For example, if `I18n.default_locale` is `:en`, the index will be generated as follows:
325
-
326
- ```ruby
327
- slug :title, localize: true
328
-
329
- # The following index is auto-generated:
330
- index({ '_slugs.en' => 1 }, { unique: true, sparse: true })
331
- ```
332
-
333
- If you are supporting multiple locales, you may specify the list of locales on which
334
- to create indexes as an `Array`.
335
-
336
- ```ruby
337
- slug :title, localize: [:fr, :es, :de]
338
-
339
- # The following indexes are auto-generated:
340
- index({ '_slugs.fr' => 1 }, { unique: true, sparse: true })
341
- index({ '_slugs.es' => 1 }, { unique: true, sparse: true })
342
- index({ '_slugs.de' => 1 }, { unique: true, sparse: true })
343
- ```
344
-
345
- ### Custom Find Strategies
346
-
347
- By default find will search for the document by the id field if the provided id looks like a `BSON::ObjectId`, and it will otherwise find by the _slugs field. However, custom strategies can ovveride the default behavior, like e.g:
348
-
349
- ```ruby
350
- module Mongoid::Slug::UuidIdStrategy
351
- def self.call id
352
- id =~ /\A([0-9a-fA-F]){8}-(([0-9a-fA-F]){4}-){3}([0-9a-fA-F]){12}\z/
353
- end
354
- end
355
- ```
356
-
357
- Use a custom strategy by adding the `slug_id_strategy` annotation to the `_id` field:
358
-
359
- ```ruby
360
- class Entity
361
- include Mongoid::Document
362
- include Mongoid::Slug
363
-
364
- field :_id, type: String, slug_id_strategy: UuidIdStrategy
365
-
366
- field :user_edited_variation
367
- slug :user_edited_variation, history: true
368
- end
369
- ```
370
-
371
- ### Adhoc Checking Whether a Slug is Unique
372
-
373
- Lets say you want to have a auto-suggest function on your GUI that could provide a preview of what the url or slug could be before the form to create the record was submitted.
374
-
375
- You can use the UniqueSlug class in your server side code to do this, e.g.
376
-
377
- ```ruby
378
- title = params[:title]
379
- unique = Mongoid::Slug::UniqueSlug.new(Book.new).find_unique(title)
380
- ...
381
- # return some representation of unique
382
- ```
383
-
384
- Contributing
385
- ------------
386
-
387
- Mongoid-slug is work of [many of contributors](https://github.com/mongoid/mongoid-slug/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/mongoid/mongoid-slug/pulls), [propose features, ask questions and discuss issues](https://github.com/mongoid/mongoid-slug/issues). See [CONTRIBUTING](CONTRIBUTING.md) for details.
388
-
389
- Copyright & License
390
- -------------------
391
-
392
- Copyright (c) 2010-2017 Hakan Ensari & Contributors, see [LICENSE](LICENSE) for details.
1
+ Mongoid Slug
2
+ ============
3
+
4
+ Mongoid Slug generates a URL slug or permalink based on one or more fields in a Mongoid model.
5
+ It sits idly on top of [stringex](https://github.com/rsl/stringex), supporting non-Latin characters.
6
+
7
+ [![Build Status](https://github.com/mongoid/mongoid-slug/actions/workflows/test.yml/badge.svg?query=branch%3Amaster)](https://github.com/mongoid/mongoid-slug/actions/workflows/test.ym?query=branch%3Amaster)
8
+ [![Gem Version](https://badge.fury.io/rb/mongoid-slug.svg)](http://badge.fury.io/rb/mongoid-slug)
9
+ [![Code Climate](https://codeclimate.com/github/mongoid/mongoid-slug.svg)](https://codeclimate.com/github/mongoid/mongoid-slug)
10
+
11
+ ### Version Support
12
+
13
+ Mongoid Slug 7.x requires at least Mongoid 7.0.0 and Ruby 2.7.0. For earlier Mongoid and Ruby version support, please use an earlier version of Mongoid Slug.
14
+
15
+ Mongoid Slug is compatible with all MongoDB versions which Mongoid supports, however, please see "Slug Max Length" section below for MongoDB 4.0 and earlier.
16
+
17
+ ### Installation
18
+
19
+ Add to your Gemfile:
20
+
21
+ ```ruby
22
+ gem 'mongoid-slug'
23
+ ```
24
+
25
+ ### Usage
26
+
27
+ ### Set Up a Slug
28
+
29
+ ```ruby
30
+ class Book
31
+ include Mongoid::Document
32
+ include Mongoid::Slug
33
+
34
+ field :title
35
+ slug :title
36
+ end
37
+ ```
38
+
39
+ ### Find a Document by its Slug
40
+
41
+ ```ruby
42
+ # GET /books/a-thousand-plateaus
43
+ book = Book.find params[:book_id]
44
+ ```
45
+
46
+ Mongoid Slug will attempt to determine whether you want to find using the `slugs` field or the `_id` field by inspecting the supplied parameters.
47
+
48
+ * Mongoid Slug will perform a find based on `slugs` only if all arguments passed to `find` are of the type `String`.
49
+ * If your document uses `BSON::ObjectId` identifiers, and all arguments look like valid `BSON::ObjectId`, then Mongoid Slug will perform a find based on `_id`.
50
+ * If your document uses any other type of identifiers, and all arguments passed to `find` are of the same type, then Mongoid Slug will perform a find based on `_id`.
51
+ * If your document uses `String` identifiers and you want to be able find by slugs or ids, to get the correct behaviour, you should add a `slug_id_strategy` option to your `_id` field definition. This option should return something that responds to `call` (a callable) and takes one string argument, e.g. a lambda. This callable must return true if the string looks like one of your ids.
52
+
53
+ ```ruby
54
+ Book.fields['_id'].type
55
+ => String
56
+
57
+ book = Book.find 'a-thousand-plateaus' # Finds by slugs
58
+ => ...
59
+
60
+ class Post
61
+ include Mongoid::Document
62
+ include Mongoid::Slug
63
+
64
+ field :_id, type: String, slug_id_strategy: lambda { |id| id.start_with?('...') }
65
+
66
+ field :name
67
+ slug :name, history: true
68
+ end
69
+
70
+ Post.fields['_id'].type
71
+ => String
72
+
73
+ post = Post.find 'a-thousand-plateaus' # Finds by slugs
74
+ => ...
75
+
76
+ post = Post.find '50b1386a0482939864000001' # Finds by bson ids
77
+ => ...
78
+ ```
79
+
80
+ [Examine slug.rb](lib/mongoid/slug.rb) for all available options.
81
+
82
+ ### Updating Existing Records
83
+
84
+ To set slugs for existing records run following rake task:
85
+
86
+ ```ruby
87
+ rake mongoid_slug:set
88
+ ```
89
+
90
+ You can pass model names as an option for which you want to set slugs:
91
+
92
+ ```ruby
93
+ rake mongoid_slug:set[Model1,Model2]
94
+ ```
95
+
96
+ ### Nil Slugs
97
+
98
+ Empty slugs are possible and generate a `nil` value for the `_slugs` field. In the `Post` example above, a blank post `name` will cause the document record not to contain a `_slugs` field in the database. The default `_slugs` index is `sparse`, allowing that. If you wish to change this behavior add a custom `validates_presence_of :_slugs` validator to the document or change the database index to `sparse: false`.
99
+
100
+ ### Custom Slug Generation
101
+
102
+ By default Mongoid Slug generates slugs with stringex. If this is not desired you can define your own slug generator.
103
+
104
+ There are two ways to define slug generator.
105
+
106
+ #### Globally
107
+
108
+ Configure a block in `config/initializers/mongoid_slug.rb` as follows:
109
+
110
+ ```ruby
111
+ Mongoid::Slug.configure do |c|
112
+ # create a block that takes the current object as an argument and return the slug
113
+ c.slug = proc { |cur_obj|
114
+ cur_object.slug_builder.to_url
115
+ }
116
+ end
117
+ ```
118
+
119
+ #### On Model
120
+
121
+ ```ruby
122
+ class Caption
123
+ include Mongoid::Document
124
+ include Mongoid::Slug
125
+
126
+ # create a block that takes the current object as an argument and returns the slug
127
+ slug do |cur_object|
128
+ cur_object.slug_builder.to_url
129
+ end
130
+ end
131
+ ```
132
+
133
+ The `to_url` method comes from [stringex](https://github.com/rsl/stringex).
134
+
135
+ You can define a slug builder globally and/or override it per model.
136
+
137
+ ### Indexing
138
+
139
+ By default, Mongoid Slug will automatically generate an index for the slug, which will be created when you run `rake db:create_indexes`. This index will take into account scoping and other options described below.
140
+
141
+ To skip this index generation, you may set `index: false` as follows:
142
+
143
+ ```ruby
144
+ class Employee
145
+ include Mongoid::Document
146
+ include Mongoid::Slug
147
+
148
+ field :name
149
+
150
+ slug :name, index: :false
151
+ end
152
+ ```
153
+
154
+ ### Scoping
155
+
156
+ To scope a slug by a reference association, pass `:scope`:
157
+
158
+ ```ruby
159
+ class Company
160
+ include Mongoid::Document
161
+
162
+ references_many :employees
163
+ end
164
+
165
+ class Employee
166
+ include Mongoid::Document
167
+ include Mongoid::Slug
168
+
169
+ field :name
170
+ referenced_in :company
171
+
172
+ slug :name, scope: :company
173
+ end
174
+ ```
175
+
176
+ In this example, if you create an employee without associating it with any company, the scope will fall back to the root employees collection.
177
+
178
+ Currently, if you have an irregular association name, you **must** specify the `:inverse_of` option on the other side of the assocation.
179
+
180
+ Embedded objects are automatically scoped by their parent.
181
+
182
+ Note that the unique index on the `Employee` collection in this example is derived from the `scope` value and is `{ _slugs: 1, company_id: 1}`. Therefore `:company` must be `referenced_in` above the definition of `slug` or it will not be able to resolve the association and mistakenly create a `{ _slugs: 1, company: 1}` index. An alternative is to scope to the field itself as follows:
183
+
184
+ ```ruby
185
+ class Employee
186
+ include Mongoid::Document
187
+ include Mongoid::Slug
188
+
189
+ field :name
190
+ field :company_id
191
+
192
+ slug :name, scope: :company_id
193
+ end
194
+ ```
195
+
196
+ You may scope slugs using multiple fields as per the following example:
197
+
198
+ ```ruby
199
+ class Employee
200
+ include Mongoid::Document
201
+ include Mongoid::Slug
202
+
203
+ field :name
204
+ field :company_id
205
+ field :department_id
206
+
207
+ # Scope slug uniqueness by a combination of company and department
208
+ slug :name, scope: %i[company_id department_id]
209
+ end
210
+ ```
211
+
212
+ ### Slug Max Length
213
+
214
+ MongoDB [featureCompatibilityVersion](https://docs.mongodb.com/manual/reference/command/setFeatureCompatibilityVersion/#std-label-view-fcv)
215
+ "4.0" and earlier applies an [Index Key Limit](https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Index-Key-Limit)
216
+ which limits the total size of an index entry to around 1KB and will raise error,
217
+ `17280 - key too large to index` when trying to create a record that causes an index key to exceed that limit.
218
+ By default slugs are of the form `text[-number]` and the text portion is limited in size
219
+ to `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes.
220
+ You can change this limit with `max_length` or set it to `nil` if you're running MongoDB
221
+ with [failIndexKeyTooLong](https://docs.mongodb.org/manual/reference/parameters/#param.failIndexKeyTooLong) set to `false`.
222
+
223
+ ```ruby
224
+ class Company
225
+ include Mongoid::Document
226
+ include Mongoid::Slug
227
+
228
+ field :name
229
+
230
+ slug :name, max_length: 24
231
+ end
232
+ ```
233
+
234
+ ### Optionally Find and Create Slugs per Model Type
235
+
236
+ By default when using STI, the scope will be around the super-class.
237
+
238
+ ```ruby
239
+ class Book
240
+ include Mongoid::Document
241
+ include Mongoid::Slug
242
+ field :title
243
+
244
+ slug :title, history: true
245
+ embeds_many :subjects
246
+ has_many :authors
247
+ end
248
+
249
+ class ComicBook < Book
250
+ end
251
+
252
+ book = Book.create(title: 'Anti Oedipus')
253
+ comic_book = ComicBook.create(title: 'Anti Oedipus')
254
+ comic_book.slugs.should_not eql(book.slugs)
255
+ ```
256
+
257
+ If you want the scope to be around the subclass, then set the option `by_model_type: true`.
258
+
259
+ ```ruby
260
+ class Book
261
+ include Mongoid::Document
262
+ include Mongoid::Slug
263
+ field :title
264
+
265
+ slug :title, history: true, by_model_type: true
266
+ embeds_many :subjects
267
+ has_many :authors
268
+ end
269
+
270
+ class ComicBook < Book
271
+ end
272
+
273
+ book = Book.create(title: 'Anti Oedipus')
274
+ comic_book = ComicBook.create(title: 'Anti Oedipus')
275
+ comic_book.slugs.should eql(book.slugs)
276
+ ```
277
+
278
+ ### History
279
+
280
+ Enable slug history tracking by setting `history: true`.
281
+
282
+ ```ruby
283
+ class Page
284
+ include Mongoid::Document
285
+ include Mongoid::Slug
286
+
287
+ field :title
288
+
289
+ slug :title, history: true
290
+ end
291
+ ```
292
+
293
+ The document will then be returned for any of the saved slugs:
294
+
295
+ ```ruby
296
+ page = Page.new title: "Home"
297
+ page.save
298
+ page.update_attributes title: "Welcome"
299
+
300
+ Page.find("welcome") == Page.find("home") # => true
301
+ ```
302
+
303
+ ### Reserved Slugs
304
+
305
+ Pass words you do not want to be slugged using the `reserve` option:
306
+
307
+ ```ruby
308
+ class Friend
309
+ include Mongoid::Document
310
+
311
+ field :name
312
+ slug :name, reserve: ['admin', 'root']
313
+ end
314
+
315
+ friend = Friend.create name: 'admin'
316
+ Friend.find('admin') # => nil
317
+ friend.slug # => 'admin-1'
318
+ ```
319
+
320
+ When reserved words are not specified, the words 'new' and 'edit' are considered reserved by default.
321
+ Specifying an array of custom reserved words will overwrite these defaults.
322
+
323
+ ### Localize Slugs
324
+
325
+ The slugs can be localized. This feature is built upon Mongoid localized fields,
326
+ so fallbacks and localization works as documented in the Mongoid manual.
327
+
328
+ ```ruby
329
+ class PageSlugLocalize
330
+ include Mongoid::Document
331
+ include Mongoid::Slug
332
+
333
+ field :title, localize: true
334
+ slug :title, localize: true
335
+ end
336
+ ```
337
+
338
+ By specifying `localize: true`, the slug index will be created on the
339
+ [I18n.default_locale](http://guides.rubyonrails.org/i18n.html#the-public-i18n-api) field only.
340
+ For example, if `I18n.default_locale` is `:en`, the index will be generated as follows:
341
+
342
+ ```ruby
343
+ slug :title, localize: true
344
+
345
+ # The following index is auto-generated:
346
+ index({ '_slugs.en' => 1 }, { unique: true, sparse: true })
347
+ ```
348
+
349
+ If you are supporting multiple locales, you may specify the list of locales on which
350
+ to create indexes as an `Array`.
351
+
352
+ ```ruby
353
+ slug :title, localize: [:fr, :es, :de]
354
+
355
+ # The following indexes are auto-generated:
356
+ index({ '_slugs.fr' => 1 }, { unique: true, sparse: true })
357
+ index({ '_slugs.es' => 1 }, { unique: true, sparse: true })
358
+ index({ '_slugs.de' => 1 }, { unique: true, sparse: true })
359
+ ```
360
+
361
+ ### Custom Find Strategies
362
+
363
+ By default find will search for the document by the id field if the provided id looks like a `BSON::ObjectId`, and it will otherwise find by the _slugs field. However, custom strategies can ovveride the default behavior, like e.g:
364
+
365
+ ```ruby
366
+ module Mongoid::Slug::UuidIdStrategy
367
+ def self.call id
368
+ id =~ /\A([0-9a-fA-F]){8}-(([0-9a-fA-F]){4}-){3}([0-9a-fA-F]){12}\z/
369
+ end
370
+ end
371
+ ```
372
+
373
+ Use a custom strategy by adding the `slug_id_strategy` annotation to the `_id` field:
374
+
375
+ ```ruby
376
+ class Entity
377
+ include Mongoid::Document
378
+ include Mongoid::Slug
379
+
380
+ field :_id, type: String, slug_id_strategy: UuidIdStrategy
381
+
382
+ field :user_edited_variation
383
+ slug :user_edited_variation, history: true
384
+ end
385
+ ```
386
+
387
+ ### Adhoc Checking Whether a Slug is Unique
388
+
389
+ Lets say you want to have a auto-suggest function on your GUI that could provide a preview of what the url or slug could be before the form to create the record was submitted.
390
+
391
+ You can use the UniqueSlug class in your server side code to do this, e.g.
392
+
393
+ ```ruby
394
+ title = params[:title]
395
+ unique = Mongoid::Slug::UniqueSlug.new(Book.new).find_unique(title)
396
+ ...
397
+ # return some representation of unique
398
+ ```
399
+
400
+ Contributing
401
+ ------------
402
+
403
+ Mongoid-slug is work of [many of contributors](https://github.com/mongoid/mongoid-slug/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/mongoid/mongoid-slug/pulls), [propose features, ask questions and discuss issues](https://github.com/mongoid/mongoid-slug/issues). See [CONTRIBUTING](CONTRIBUTING.md) for details.
404
+
405
+ Copyright & License
406
+ -------------------
407
+
408
+ Copyright (c) 2010-2017 Hakan Ensari & Contributors, see [LICENSE](LICENSE) for details.