mongoid-slug 5.2.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d38815d369307746d6c796167d08b99aae02f8d
4
- data.tar.gz: e0f6c6ba7dc2431fe84de87a6b32dcc90ba1f2ba
3
+ metadata.gz: bda81e5e78c0e83e9785ff87f5b6e1f6b4ca637a
4
+ data.tar.gz: f89a8f074c6ac112b65a62b9a0e122cabaef1d54
5
5
  SHA512:
6
- metadata.gz: c4a7f3f5d7fdf36cb4d64b0ae5bb9f1e35bc6c2dbad3a7d1bbd586ff46b0a0da957bd3762bbe88182595b1aeb9b4e59c6a88bd143bbcdc3f17498c1a60ff82be
7
- data.tar.gz: c91cb32733b81ec8b1ace9528bfced0c019aa1fc96d88cc4b6e11d803af0509cee3a0098260de8abcfd7702207deda9cd1c813b3f73f3a12f14930880d08c94c
6
+ metadata.gz: b30566749607cda56d2b4ed929327978f8997adca09a08a2f66b2b375a5f5485a9967c2c178bf7aa6433d78345d75b814a729f3c98e85f4195e81d1fe9880be8
7
+ data.tar.gz: 37c91ae5d6984e3403123e7bab3e568cbce7540d002509d5d3bfa396fd2fc72f8d8096498c933dae180aceec8f5edc09fda6e4a5fe1b9c0bbb1a40ed935ce76f
data/README.md CHANGED
@@ -3,13 +3,12 @@ Mongoid Slug
3
3
 
4
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
5
 
6
- [![Build Status](https://secure.travis-ci.org/digitalplaywright/mongoid-slug.svg)](http://travis-ci.org/digitalplaywright/mongoid-slug)
6
+ [![Build Status](https://secure.travis-ci.org/mongoid/mongoid-slug.svg)](http://travis-ci.org/mongoid/mongoid-slug)
7
7
  [![Gem Version](https://badge.fury.io/rb/mongoid-slug.svg)](http://badge.fury.io/rb/mongoid-slug)
8
- [![Dependency Status](https://gemnasium.com/digitalplaywright/mongoid-slug.svg)](https://gemnasium.com/digitalplaywright/mongoid-slug)
9
- [![Code Climate](https://codeclimate.com/github/digitalplaywright/mongoid-slug.svg)](https://codeclimate.com/github/digitalplaywright/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
10
 
11
- Installation
12
- ------------
11
+ ### Installation
13
12
 
14
13
  Add to your Gemfile:
15
14
 
@@ -17,10 +16,9 @@ Add to your Gemfile:
17
16
  gem 'mongoid-slug'
18
17
  ```
19
18
 
20
- Usage
21
- -----
19
+ ### Usage
22
20
 
23
- Set up a slug:
21
+ ### Set Up a Slug
24
22
 
25
23
  ```ruby
26
24
  class Book
@@ -32,7 +30,7 @@ class Book
32
30
  end
33
31
  ```
34
32
 
35
- Find a document by its slug:
33
+ ### Find a Document by its Slug
36
34
 
37
35
  ```ruby
38
36
  # GET /books/a-thousand-plateaus
@@ -41,11 +39,10 @@ book = Book.find params[:book_id]
41
39
 
42
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.
43
41
 
44
- * Mongoid Slug will perform a find based on `slugs` only if all arguments passed to `find` are of the type `String`
42
+ * Mongoid Slug will perform a find based on `slugs` only if all arguments passed to `find` are of the type `String`.
45
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`.
46
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`.
47
- * 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.
48
-
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.
49
46
 
50
47
  ```ruby
51
48
  Book.fields['_id'].type
@@ -57,7 +54,7 @@ class Post
57
54
  include Mongoid::Document
58
55
  include Mongoid::Slug
59
56
 
60
- field :_id, type: String, slug_id_strategy: lambda {|id| id.start_with?('....')}
57
+ field :_id, type: String, slug_id_strategy: lambda { |id| id.start_with?('...') }
61
58
 
62
59
  field :name
63
60
  slug :name, history: true
@@ -72,38 +69,62 @@ post = Post.find '50b1386a0482939864000001' # Finds by bson ids
72
69
  ```
73
70
  [Examine slug.rb](lib/mongoid/slug.rb) for all available options.
74
71
 
72
+ ### Updating Existing Records
73
+
75
74
  To set slugs for existing records run following rake task:
76
75
 
77
76
  ```ruby
78
77
  rake mongoid_slug:set
79
78
  ```
79
+
80
80
  You can pass model names as an option for which you want to set slugs:
81
81
 
82
82
  ```ruby
83
83
  rake mongoid_slug:set[Model1,Model2]
84
84
  ```
85
- Custom Slug Generation
86
- -------
87
85
 
88
- By default Mongoid Slug generates slugs with stringex. If this is not desired you can
89
- define your own slug generator like this:
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
90
110
 
91
111
  ```ruby
92
112
  class Caption
93
113
  include Mongoid::Document
94
114
  include Mongoid::Slug
95
115
 
96
- #create a block that takes the current object as an argument
97
- #and returns the slug.
116
+ # create a block that takes the current object as an argument and returns the slug
98
117
  slug do |cur_object|
99
118
  cur_object.slug_builder.to_url
100
119
  end
101
120
  end
102
121
  ```
103
- You can call stringex `to_url` method.
104
122
 
105
- Scoping
106
- -------
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
107
128
 
108
129
  To scope a slug by a reference association, pass `:scope`:
109
130
 
@@ -121,19 +142,17 @@ class Employee
121
142
  field :name
122
143
  referenced_in :company
123
144
 
124
- slug :name, scope: :company
145
+ slug :name, scope: :company
125
146
  end
126
147
  ```
127
148
 
128
- In this example, if you create an employee without associating it with any
129
- company, the scope will fall back to the root employees collection.
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.
130
150
 
131
- Currently, if you have an irregular association name, you **must** specify the
132
- `:inverse_of` option on the other side of the assocation.
151
+ Currently, if you have an irregular association name, you **must** specify the `:inverse_of` option on the other side of the assocation.
133
152
 
134
153
  Embedded objects are automatically scoped by their parent.
135
154
 
136
- The value of `:scope` can alternatively be a field within the model itself:
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:
137
156
 
138
157
  ```ruby
139
158
  class Employee
@@ -143,12 +162,11 @@ class Employee
143
162
  field :name
144
163
  field :company_id
145
164
 
146
- slug :name, scope: :company_id
165
+ slug :name, scope: :company_id
147
166
  end
148
167
  ```
149
168
 
150
- Limit Slug Length
151
- -----------------
169
+ ### Limit Slug Length
152
170
 
153
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`.
154
172
 
@@ -163,8 +181,7 @@ class Company
163
181
  end
164
182
  ```
165
183
 
166
- Optionally Find and Create Slugs per Model Type
167
- -----------------------------------------------
184
+ ### Optionally Find and Create Slugs per Model Type
168
185
 
169
186
  By default when using STI, the scope will be around the super-class.
170
187
 
@@ -208,11 +225,9 @@ comic_book = ComicBook.create(title: 'Anti Oedipus')
208
225
  comic_book.slugs.should eql(book.slugs)
209
226
  ```
210
227
 
211
- History
212
- -------
228
+ ### History
213
229
 
214
- To specify that the history of a document should be kept track of, pass
215
- `:history` with a value of `true`.
230
+ Enable slug history tracking by setting `history: true`.
216
231
 
217
232
  ```ruby
218
233
  class Page
@@ -235,8 +250,7 @@ page.update_attributes title: "Welcome"
235
250
  Page.find("welcome") == Page.find("home") # => true
236
251
  ```
237
252
 
238
- Reserved Slugs
239
- --------------
253
+ ### Reserved Slugs
240
254
 
241
255
  Pass words you do not want to be slugged using the `reserve` option:
242
256
 
@@ -256,10 +270,9 @@ friend.slug # => 'admin-1'
256
270
  When reserved words are not specified, the words 'new' and 'edit' are considered reserved by default.
257
271
  Specifying an array of custom reserved words will overwrite these defaults.
258
272
 
259
- Localize Slug
260
- --------------
273
+ ### Localize Slugs
261
274
 
262
- The slug can be localized:
275
+ The slugs can be localized:
263
276
 
264
277
  ```ruby
265
278
  class PageSlugLocalize
@@ -271,18 +284,11 @@ class PageSlugLocalize
271
284
  end
272
285
  ```
273
286
 
274
- This feature is built upon Mongoid localized fields, so fallbacks and localization
275
- works as documented in the Mongoid manual.
287
+ This feature is built upon Mongoid localized fields, so fallbacks and localization works as documented in the Mongoid manual.
276
288
 
277
- PS! A migration is needed to use Mongoid localized fields for documents that was created when this
278
- feature was off. Anything else will cause errors.
289
+ ### Custom Find Strategies
279
290
 
280
- Custom Find Strategies
281
- ----------------------
282
-
283
- By default find will search for the document by the id field if the provided id
284
- looks like a BSON::ObjectId, and it will otherwise find by the _slugs field. However,
285
- custom strategies can ovveride the default behavior, like e.g:
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:
286
292
 
287
293
  ```ruby
288
294
  module Mongoid::Slug::UuidIdStrategy
@@ -292,7 +298,7 @@ module Mongoid::Slug::UuidIdStrategy
292
298
  end
293
299
  ```
294
300
 
295
- Use a custom strategy by adding the slug_id_strategy annotation to the _id field:
301
+ Use a custom strategy by adding the `slug_id_strategy` annotation to the `_id` field:
296
302
 
297
303
  ```ruby
298
304
  class Entity
@@ -306,9 +312,7 @@ class Entity
306
312
  end
307
313
  ```
308
314
 
309
-
310
- Adhoc checking whether a string is unique on a per Model basis
311
- --------------------------------------------------------------
315
+ ### Adhoc Checking Whether a Slug is Unique
312
316
 
313
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.
314
318
 
@@ -321,17 +325,16 @@ unique = Mongoid::Slug::UniqueSlug.new(Book.new).find_unique(title)
321
325
  # return some representation of unique
322
326
  ```
323
327
 
324
-
325
- Mongoid::Paranoia Support
326
- -------------------------
328
+ ### Mongoid::Paranoia Support
327
329
 
328
330
  The [Mongoid::Paranoia](http://github.com/simi/mongoid-paranoia) gem adds "soft-destroy" functionality to Mongoid documents.
331
+
329
332
  Mongoid::Slug contains special handling for Mongoid::Paranoia:
330
333
 
331
- - When destroying a paranoid document, the slug will be unset from the database.
332
- - When restoring a paranoid document, the slug will be rebuilt. Note that the new slug may not match the old one.
333
- - When resaving a destroyed paranoid document, the slug will remain unset in the database.
334
- - For indexing purposes, sparse unique indexes are used. The sparse condition will ignore any destroyed paranoid documents, since their slug is not set in database.
334
+ * When destroying a paranoid document, the slug will be unset from the database.
335
+ * When restoring a paranoid document, the slug will be rebuilt. Note that the new slug may not match the old one.
336
+ * When resaving a destroyed paranoid document, the slug will remain unset in the database.
337
+ * For indexing purposes, sparse unique indexes are used. The sparse condition will ignore any destroyed paranoid documents, since their slug is not set in database.
335
338
 
336
339
  ```ruby
337
340
  class Entity
@@ -343,17 +346,15 @@ end
343
346
 
344
347
  The following variants of Mongoid Paranoia are officially supported:
345
348
 
346
- * Mongoid 3 built-in Mongoid::Paranoia
349
+ * Mongoid 3 built-in `Mongoid::Paranoia`
347
350
  * Mongoid 4 or 5 gem http://github.com/simi/mongoid_paranoia
348
351
 
349
-
350
352
  Contributing
351
353
  ------------
352
354
 
353
- Mongoid-slug is work of [many of contributors](https://github.com/digitalplaywright/mongoid-slug/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/digitalplaywright/mongoid-slug/pulls), [propose features, ask questions and discuss issues](https://github.com/digitalplaywright/mongoid-slug/issues). See [CONTRIBUTING](CONTRIBUTING.md) for details.
355
+ 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.
354
356
 
355
357
  Copyright & License
356
358
  -------------------
357
359
 
358
360
  Copyright (c) 2010-2016 Hakan Ensari & Contributors, see [LICENSE](LICENSE) for details.
359
-
@@ -16,18 +16,29 @@ module Mongoid
16
16
  MONGO_INDEX_KEY_LIMIT_BYTES = 1024
17
17
 
18
18
  included do
19
- cattr_accessor :reserved_words,
19
+ cattr_accessor :slug_reserved_words,
20
20
  :slug_scope,
21
21
  :slugged_attributes,
22
- :url_builder,
23
- :history,
24
- :by_model_type,
22
+ :slug_url_builder,
23
+ :slug_history,
24
+ :slug_by_model_type,
25
25
  :slug_max_length
26
26
 
27
27
  # field :_slugs, type: Array, default: [], localize: false
28
28
  # alias_attribute :slugs, :_slugs
29
29
  end
30
30
 
31
+ class << self
32
+ attr_accessor :default_slug
33
+ def configure(&block)
34
+ instance_eval(&block)
35
+ end
36
+
37
+ def slug(&block)
38
+ @default_slug = block if block_given?
39
+ end
40
+ end
41
+
31
42
  module ClassMethods
32
43
  # @overload slug(*fields)
33
44
  # Sets one ore more fields as source of slug.
@@ -65,26 +76,21 @@ module Mongoid
65
76
  options = fields.extract_options!
66
77
 
67
78
  self.slug_scope = options[:scope]
68
- self.reserved_words = options[:reserve] || Set.new(%w(new edit))
79
+ self.slug_reserved_words = options[:reserve] || Set.new(%w(new edit))
69
80
  self.slugged_attributes = fields.map(&:to_s)
70
- self.history = options[:history]
71
- self.by_model_type = options[:by_model_type]
81
+ self.slug_history = options[:history]
82
+ self.slug_by_model_type = options[:by_model_type]
72
83
  self.slug_max_length = options.key?(:max_length) ? options[:max_length] : MONGO_INDEX_KEY_LIMIT_BYTES - 32
73
84
 
74
- field :_slugs, type: Array, default: [], localize: options[:localize]
85
+ field :_slugs, type: Array, localize: options[:localize]
75
86
  alias_attribute :slugs, :_slugs
76
87
 
77
88
  # Set index
78
89
  unless embedded?
79
- index(*Mongoid::Slug::Index.build_index(slug_scope_key, by_model_type))
90
+ index(*Mongoid::Slug::Index.build_index(slug_scope_key, slug_by_model_type))
80
91
  end
81
92
 
82
- #-- Why is it necessary to customize the slug builder?
83
- default_url_builder = lambda do |cur_object|
84
- cur_object.slug_builder.to_url
85
- end
86
-
87
- self.url_builder = block_given? ? block : default_url_builder
93
+ self.slug_url_builder = block_given? ? block : default_slug_url_builder
88
94
 
89
95
  #-- always create slug on create
90
96
  #-- do not create new slug on update if the slug is permanent
@@ -100,7 +106,7 @@ module Mongoid
100
106
  # - recreate the slug on restore
101
107
  # - force reset the slug when saving a destroyed paranoid document, to ensure it stays unset in the database
102
108
  if is_paranoid_doc?
103
- send(:include, Mongoid::Slug::Paranoia) unless self.respond_to?(:before_restore)
109
+ send(:include, Mongoid::Slug::Paranoia) unless respond_to?(:before_restore)
104
110
  set_callback :destroy, :after, :unset_slug!
105
111
  set_callback :restore, :before, :set_slug!
106
112
  set_callback :save, :before, :reset_slug!, if: :paranoid_deleted?
@@ -108,6 +114,10 @@ module Mongoid
108
114
  end
109
115
  end
110
116
 
117
+ def default_slug_url_builder
118
+ Mongoid::Slug.default_slug || ->(cur_object) { cur_object.slug_builder.to_url }
119
+ end
120
+
111
121
  def look_like_slugs?(*args)
112
122
  with_default_scope.look_like_slugs?(*args)
113
123
  end
@@ -158,11 +168,13 @@ module Mongoid
158
168
 
159
169
  private
160
170
 
161
- if Mongoid::Compatibility::Version.mongoid5? && Threaded.method(:current_scope).arity == -1
171
+ if Mongoid::Compatibility::Version.mongoid5? ||
172
+ Mongoid::Compatibility::Version.mongoid6? &&
173
+ Threaded.method(:current_scope).arity == -1
162
174
  def current_scope
163
175
  Threaded.current_scope(self)
164
176
  end
165
- elsif Mongoid::Compatibility::Version.mongoid5?
177
+ elsif Mongoid::Compatibility::Version.mongoid5? || Mongoid::Compatibility::Version.mongoid6?
166
178
  def current_scope
167
179
  Threaded.current_scope
168
180
  end
@@ -198,12 +210,12 @@ module Mongoid
198
210
 
199
211
  # skip slug generation and use Mongoid id
200
212
  # to find document instead
201
- return true if new_slug.size == 0
213
+ return true if new_slug.size.zero?
202
214
 
203
215
  # avoid duplicate slugs
204
216
  _slugs.delete(new_slug) if _slugs
205
217
 
206
- if !!history && _slugs.is_a?(Array)
218
+ if !!slug_history && _slugs.is_a?(Array)
207
219
  append_slug(new_slug)
208
220
  else
209
221
  self._slugs = [new_slug]
@@ -231,7 +243,7 @@ module Mongoid
231
243
 
232
244
  # Rolls back the slug value from the Mongoid changeset.
233
245
  def reset_slug!
234
- self.reset__slugs!
246
+ reset__slugs!
235
247
  end
236
248
 
237
249
  # Sets the slug to its default value.
@@ -341,7 +353,7 @@ module Mongoid
341
353
  # have any localized attributes at all (extreme edge case).
342
354
  def all_locales
343
355
  locales = slugged_attributes
344
- .map { |attr| send("#{attr}_translations").keys if self.respond_to?("#{attr}_translations") }
356
+ .map { |attr| send("#{attr}_translations").keys if respond_to?("#{attr}_translations") }
345
357
  .flatten.compact.uniq
346
358
  locales = I18n.available_locales if locales.empty?
347
359
  locales
@@ -62,7 +62,7 @@ module Mongoid
62
62
  # otherwise default for all other id_types
63
63
  def build_slug_strategy(id_type)
64
64
  type_method = id_type.to_s.downcase.split('::').last + '_slug_strategy'
65
- self.respond_to?(type_method, true) ? method(type_method) : ->(_id) { false }
65
+ respond_to?(type_method, true) ? method(type_method) : ->(_id) { false }
66
66
  end
67
67
 
68
68
  # a string will not look like a slug if it looks like a legal BSON::ObjectId
@@ -99,10 +99,8 @@ module Mongoid
99
99
 
100
100
  def check_for_missing_documents_for_slugs!(result, slugs)
101
101
  missing_slugs = slugs - result.map(&:slugs).flatten
102
-
103
- if !missing_slugs.blank? && Mongoid.raise_not_found_error
104
- fail Errors::DocumentNotFound.new(klass, slugs, missing_slugs)
105
- end
102
+ return unless !missing_slugs.blank? && Mongoid.raise_not_found_error
103
+ raise Errors::DocumentNotFound.new(klass, slugs, missing_slugs)
106
104
  end
107
105
  end
108
106
  end