mongoid-slug 6.0.0 → 7.0.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +20 -20
  3. data/README.md +392 -336
  4. data/lib/mongoid/slug/criteria.rb +111 -107
  5. data/lib/mongoid/slug/{index.rb → index_builder.rb} +69 -45
  6. data/lib/mongoid/slug/railtie.rb +11 -9
  7. data/lib/mongoid/slug/slug_id_strategy.rb +5 -3
  8. data/lib/mongoid/slug/unique_slug.rb +172 -173
  9. data/lib/mongoid/slug/version.rb +7 -5
  10. data/lib/mongoid/slug.rb +333 -328
  11. data/lib/mongoid_slug.rb +4 -2
  12. data/lib/tasks/mongoid_slug.rake +17 -19
  13. metadata +13 -173
  14. data/spec/models/alias.rb +0 -6
  15. data/spec/models/article.rb +0 -9
  16. data/spec/models/artist.rb +0 -8
  17. data/spec/models/artwork.rb +0 -10
  18. data/spec/models/author.rb +0 -15
  19. data/spec/models/author_polymorphic.rb +0 -15
  20. data/spec/models/book.rb +0 -12
  21. data/spec/models/book_polymorphic.rb +0 -12
  22. data/spec/models/caption.rb +0 -17
  23. data/spec/models/entity.rb +0 -11
  24. data/spec/models/friend.rb +0 -7
  25. data/spec/models/incorrect_slug_persistence.rb +0 -9
  26. data/spec/models/integer_id.rb +0 -9
  27. data/spec/models/magazine.rb +0 -7
  28. data/spec/models/page.rb +0 -9
  29. data/spec/models/page_localize.rb +0 -9
  30. data/spec/models/page_slug_localized.rb +0 -9
  31. data/spec/models/page_slug_localized_custom.rb +0 -10
  32. data/spec/models/page_slug_localized_history.rb +0 -9
  33. data/spec/models/partner.rb +0 -7
  34. data/spec/models/person.rb +0 -12
  35. data/spec/models/relationship.rb +0 -8
  36. data/spec/models/string_id.rb +0 -9
  37. data/spec/models/subject.rb +0 -7
  38. data/spec/models/without_slug.rb +0 -5
  39. data/spec/mongoid/criteria_spec.rb +0 -207
  40. data/spec/mongoid/index_spec.rb +0 -33
  41. data/spec/mongoid/slug_spec.rb +0 -1169
  42. data/spec/shared/indexes.rb +0 -41
  43. data/spec/spec_helper.rb +0 -61
  44. data/spec/tasks/mongoid_slug_rake_spec.rb +0 -73
data/README.md CHANGED
@@ -1,336 +1,392 @@
1
- Mongoid Slug
2
- ============
3
-
4
- Mongoid Slug generates a URL slug or permalink based on one or more fields in a Mongoid model. It sits idly on top of [stringex](https://github.com/rsl/stringex), supporting non-Latin characters.
5
-
6
- [![Build Status](https://secure.travis-ci.org/mongoid/mongoid-slug.svg)](http://travis-ci.org/mongoid/mongoid-slug)
7
- [![Gem Version](https://badge.fury.io/rb/mongoid-slug.svg)](http://badge.fury.io/rb/mongoid-slug)
8
- [![Dependency Status](https://gemnasium.com/mongoid/mongoid-slug.svg)](https://gemnasium.com/mongoid/mongoid-slug)
9
- [![Code Climate](https://codeclimate.com/github/mongoid/mongoid-slug.svg)](https://codeclimate.com/github/mongoid/mongoid-slug)
10
-
11
- ### Installation
12
-
13
- Add to your Gemfile:
14
-
15
- ```ruby
16
- gem 'mongoid-slug'
17
- ```
18
-
19
- ### Usage
20
-
21
- ### Set Up a Slug
22
-
23
- ```ruby
24
- class Book
25
- include Mongoid::Document
26
- include Mongoid::Slug
27
-
28
- field :title
29
- slug :title
30
- end
31
- ```
32
-
33
- ### Find a Document by its Slug
34
-
35
- ```ruby
36
- # GET /books/a-thousand-plateaus
37
- book = Book.find params[:book_id]
38
- ```
39
-
40
- Mongoid Slug will attempt to determine whether you want to find using the `slugs` field or the `_id` field by inspecting the supplied parameters.
41
-
42
- * Mongoid Slug will perform a find based on `slugs` only if all arguments passed to `find` are of the type `String`.
43
- * 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`.
44
- * 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`.
45
- * 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.
46
-
47
- ```ruby
48
- Book.fields['_id'].type
49
- => String
50
- book = Book.find 'a-thousand-plateaus' # Finds by slugs
51
- => ...
52
-
53
- class Post
54
- include Mongoid::Document
55
- include Mongoid::Slug
56
-
57
- field :_id, type: String, slug_id_strategy: lambda { |id| id.start_with?('...') }
58
-
59
- field :name
60
- slug :name, history: true
61
- end
62
-
63
- Post.fields['_id'].type
64
- => String
65
- post = Post.find 'a-thousand-plateaus' # Finds by slugs
66
- => ...
67
- post = Post.find '50b1386a0482939864000001' # Finds by bson ids
68
- => ...
69
- ```
70
- [Examine slug.rb](lib/mongoid/slug.rb) for all available options.
71
-
72
- ### Updating Existing Records
73
-
74
- To set slugs for existing records run following rake task:
75
-
76
- ```ruby
77
- rake mongoid_slug:set
78
- ```
79
-
80
- You can pass model names as an option for which you want to set slugs:
81
-
82
- ```ruby
83
- rake mongoid_slug:set[Model1,Model2]
84
- ```
85
-
86
- ### Nil Slugs
87
-
88
- 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`.
89
-
90
- ### Custom Slug Generation
91
-
92
- By default Mongoid Slug generates slugs with stringex. If this is not desired you can define your own slug generator.
93
-
94
- There are two ways to define slug generator.
95
-
96
- #### Globally
97
-
98
- Configure a block in `config/initializers/mongoid_slug.rb` as follows:
99
-
100
- ```ruby
101
- Mongoid::Slug.configure do |c|
102
- # create a block that takes the current object as an argument and return the slug
103
- c.slug = proc { |cur_obj|
104
- cur_object.slug_builder.to_url
105
- }
106
- end
107
- ```
108
-
109
- #### On Model
110
-
111
- ```ruby
112
- class Caption
113
- include Mongoid::Document
114
- include Mongoid::Slug
115
-
116
- # create a block that takes the current object as an argument and returns the slug
117
- slug do |cur_object|
118
- cur_object.slug_builder.to_url
119
- end
120
- end
121
- ```
122
-
123
- The `to_url` method comes from [stringex](https://github.com/rsl/stringex).
124
-
125
- You can define a slug builder globally and/or override it per model.
126
-
127
- ### Scoping
128
-
129
- To scope a slug by a reference association, pass `:scope`:
130
-
131
- ```ruby
132
- class Company
133
- include Mongoid::Document
134
-
135
- references_many :employees
136
- end
137
-
138
- class Employee
139
- include Mongoid::Document
140
- include Mongoid::Slug
141
-
142
- field :name
143
- referenced_in :company
144
-
145
- slug :name, scope: :company
146
- end
147
- ```
148
-
149
- In this example, if you create an employee without associating it with any company, the scope will fall back to the root employees collection.
150
-
151
- Currently, if you have an irregular association name, you **must** specify the `:inverse_of` option on the other side of the assocation.
152
-
153
- Embedded objects are automatically scoped by their parent.
154
-
155
- 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:
156
-
157
- ```ruby
158
- class Employee
159
- include Mongoid::Document
160
- include Mongoid::Slug
161
-
162
- field :name
163
- field :company_id
164
-
165
- slug :name, scope: :company_id
166
- end
167
- ```
168
-
169
- ### Limit Slug Length
170
-
171
- MongoDB has a default limit around 1KB to the size of the index keys and will raise error 17280, `key too large to index` when trying to create a record that causes an index key to exceed that limit. By default slugs are of the form `text[-number]` and the text portion is limited in size to `Mongoid::Slug::MONGO_INDEX_KEY_LIMIT_BYTES - 32` bytes. You can change this limit with `max_length` or set it to `nil` if you're running MongoDB with [failIndexKeyTooLong](https://docs.mongodb.org/manual/reference/parameters/#param.failIndexKeyTooLong) set to `false`.
172
-
173
- ```ruby
174
- class Company
175
- include Mongoid::Document
176
- include Mongoid::Slug
177
-
178
- field :name
179
-
180
- slug :name, max_length: 24
181
- end
182
- ```
183
-
184
- ### Optionally Find and Create Slugs per Model Type
185
-
186
- By default when using STI, the scope will be around the super-class.
187
-
188
- ```ruby
189
- class Book
190
- include Mongoid::Document
191
- include Mongoid::Slug
192
- field :title
193
-
194
- slug :title, history: true
195
- embeds_many :subjects
196
- has_many :authors
197
- end
198
-
199
- class ComicBook < Book
200
- end
201
-
202
- book = Book.create(title: 'Anti Oedipus')
203
- comic_book = ComicBook.create(title: 'Anti Oedipus')
204
- comic_book.slugs.should_not eql(book.slugs)
205
- ```
206
-
207
- If you want the scope to be around the subclass, then set the option `by_model_type: true`.
208
-
209
- ```ruby
210
- class Book
211
- include Mongoid::Document
212
- include Mongoid::Slug
213
- field :title
214
-
215
- slug :title, history: true, by_model_type: true
216
- embeds_many :subjects
217
- has_many :authors
218
- end
219
-
220
- class ComicBook < Book
221
- end
222
-
223
- book = Book.create(title: 'Anti Oedipus')
224
- comic_book = ComicBook.create(title: 'Anti Oedipus')
225
- comic_book.slugs.should eql(book.slugs)
226
- ```
227
-
228
- ### History
229
-
230
- Enable slug history tracking by setting `history: true`.
231
-
232
- ```ruby
233
- class Page
234
- include Mongoid::Document
235
- include Mongoid::Slug
236
-
237
- field :title
238
-
239
- slug :title, history: true
240
- end
241
- ```
242
-
243
- The document will then be returned for any of the saved slugs:
244
-
245
- ```ruby
246
- page = Page.new title: "Home"
247
- page.save
248
- page.update_attributes title: "Welcome"
249
-
250
- Page.find("welcome") == Page.find("home") # => true
251
- ```
252
-
253
- ### Reserved Slugs
254
-
255
- Pass words you do not want to be slugged using the `reserve` option:
256
-
257
- ```ruby
258
- class Friend
259
- include Mongoid::Document
260
-
261
- field :name
262
- slug :name, reserve: ['admin', 'root']
263
- end
264
-
265
- friend = Friend.create name: 'admin'
266
- Friend.find('admin') # => nil
267
- friend.slug # => 'admin-1'
268
- ```
269
-
270
- When reserved words are not specified, the words 'new' and 'edit' are considered reserved by default.
271
- Specifying an array of custom reserved words will overwrite these defaults.
272
-
273
- ### Localize Slugs
274
-
275
- The slugs can be localized:
276
-
277
- ```ruby
278
- class PageSlugLocalize
279
- include Mongoid::Document
280
- include Mongoid::Slug
281
-
282
- field :title, localize: true
283
- slug :title, localize: true
284
- end
285
- ```
286
-
287
- This feature is built upon Mongoid localized fields, so fallbacks and localization works as documented in the Mongoid manual.
288
-
289
- ### Custom Find Strategies
290
-
291
- 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:
292
-
293
- ```ruby
294
- module Mongoid::Slug::UuidIdStrategy
295
- def self.call id
296
- id =~ /\A([0-9a-fA-F]){8}-(([0-9a-fA-F]){4}-){3}([0-9a-fA-F]){12}\z/
297
- end
298
- end
299
- ```
300
-
301
- Use a custom strategy by adding the `slug_id_strategy` annotation to the `_id` field:
302
-
303
- ```ruby
304
- class Entity
305
- include Mongoid::Document
306
- include Mongoid::Slug
307
-
308
- field :_id, type: String, slug_id_strategy: UuidIdStrategy
309
-
310
- field :user_edited_variation
311
- slug :user_edited_variation, history: true
312
- end
313
- ```
314
-
315
- ### Adhoc Checking Whether a Slug is Unique
316
-
317
- 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.
318
-
319
- You can use the UniqueSlug class in your server side code to do this, e.g.
320
-
321
- ```ruby
322
- title = params[:title]
323
- unique = Mongoid::Slug::UniqueSlug.new(Book.new).find_unique(title)
324
- ...
325
- # return some representation of unique
326
- ```
327
-
328
- Contributing
329
- ------------
330
-
331
- 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.
332
-
333
- Copyright & License
334
- -------------------
335
-
336
- 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
+ ### 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.