mongoid-slug 4.0.0 → 5.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.
- checksums.yaml +13 -5
- data/LICENSE +1 -1
- data/README.md +18 -18
- data/lib/mongoid/slug.rb +48 -44
- data/lib/mongoid/slug/criteria.rb +14 -11
- data/lib/mongoid/slug/index.rb +5 -8
- data/lib/mongoid/slug/paranoia.rb +0 -2
- data/lib/mongoid/slug/slug_id_strategy.rb +1 -1
- data/lib/mongoid/slug/unique_slug.rb +27 -29
- data/lib/mongoid/slug/version.rb +1 -1
- data/spec/models/alias.rb +2 -2
- data/spec/models/article.rb +1 -1
- data/spec/models/author.rb +3 -3
- data/spec/models/author_polymorphic.rb +3 -3
- data/spec/models/book.rb +1 -1
- data/spec/models/book_polymorphic.rb +1 -1
- data/spec/models/caption.rb +1 -1
- data/spec/models/entity.rb +2 -2
- data/spec/models/friend.rb +2 -2
- data/spec/models/incorrect_slug_persistence.rb +5 -5
- data/spec/models/integer_id.rb +1 -1
- data/spec/models/magazine.rb +1 -1
- data/spec/models/page.rb +3 -3
- data/spec/models/page_localize.rb +3 -3
- data/spec/models/page_slug_localized.rb +3 -3
- data/spec/models/page_slug_localized_custom.rb +0 -1
- data/spec/models/page_slug_localized_history.rb +3 -3
- data/spec/models/paranoid_document.rb +1 -1
- data/spec/models/paranoid_permanent.rb +1 -1
- data/spec/models/partner.rb +1 -1
- data/spec/models/person.rb +2 -2
- data/spec/models/relationship.rb +1 -1
- data/spec/models/string_id.rb +1 -1
- data/spec/models/subject.rb +1 -1
- data/spec/models/without_slug.rb +1 -1
- data/spec/mongoid/criteria_spec.rb +109 -109
- data/spec/mongoid/index_spec.rb +12 -14
- data/spec/mongoid/paranoia_spec.rb +78 -90
- data/spec/mongoid/slug_spec.rb +493 -492
- data/spec/shared/indexes.rb +13 -13
- data/spec/spec_helper.rb +18 -14
- metadata +51 -26
- data/spec/mongoid/slug_spec.rb.b00 +0 -1101
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NzVhMTg3OTVmNzYyZDVmNWQ1MGQxYTNiMDYyZDUzMDhkMTFiNjNkOA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDNjMmJjZTI4MDE3Njk1NThhYjg4ZTZjNmEwYzE4NzVkMjA3ZTUwNg==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NWIzMWQzYTFlNTNhNDcwY2IwN2RhM2M0M2Q5OGVkNTg1MjUzOTM1ODA5N2Rh
|
10
|
+
ZTA0NjQ0ODk0MGI5MDMzNmM4Y2I0ZDAzZWIxYzM3ZmVjOTZiYTA3NGJhZjJi
|
11
|
+
YmQyOWQxZjkwZmVmYTBkOWM4MTMxMTAzYjRhZDc2MDdhMDBiYzA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MTBkMDU5NDRlYjkxY2MyNDdjMTI1OWY4NThkYTkyNTRmMzUyZmY2ZDU4ODVl
|
14
|
+
MjU2YjNjMTRkZThiNmU3OWRmNGQ0ZTEyZTkxZTFkNDQ2ZTJkMmI2YjJmMTgx
|
15
|
+
OWQxNDEwYTQ5OTYzYzI3ZDk3MTlkMWFlNThjNTcyODJmZTI0Yjc=
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,12 @@
|
|
1
|
-
*IMPORTANT:* If you are upgrading to Mongoid Slug 1.0.0 please migrate in accordance with the instructions in https://github.com/digitalplaywright/mongoid-slug/wiki/How-to-upgrade-to-1.0.0-or-newer.
|
2
|
-
Mongoid Slug 1.0.0 stores the slugs in a single field _slugs of array type, and all previous slugs must be migrated.
|
3
|
-
|
4
1
|
Mongoid Slug
|
5
2
|
============
|
6
3
|
|
7
|
-
Mongoid Slug generates a URL slug or permalink based on one or more fields in a
|
8
|
-
Mongoid model. It sits idly on top of [stringex] [1], supporting non-Latin
|
9
|
-
characters.
|
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.
|
10
5
|
|
11
|
-
[](http://travis-ci.org/digitalplaywright/mongoid-slug)
|
6
|
+
[](http://travis-ci.org/digitalplaywright/mongoid-slug)
|
7
|
+
[](http://badge.fury.io/rb/mongoid-slug)
|
8
|
+
[](https://gemnasium.com/digitalplaywright/mongoid-slug)
|
9
|
+
[](https://codeclimate.com/github/digitalplaywright/mongoid-slug)
|
12
10
|
|
13
11
|
Installation
|
14
12
|
------------
|
@@ -72,7 +70,7 @@ post = Post.find 'a-thousand-plateaus' # Finds by slugs
|
|
72
70
|
post = Post.find '50b1386a0482939864000001' # Finds by bson ids
|
73
71
|
=> ...
|
74
72
|
```
|
75
|
-
[
|
73
|
+
[Examine slug.rb](lib/mongoid/slug.rb) for all available options.
|
76
74
|
|
77
75
|
Custom Slug Generation
|
78
76
|
-------
|
@@ -254,7 +252,7 @@ PS! A migration is needed to use Mongoid localized fields for documents that was
|
|
254
252
|
feature was off. Anything else will cause errors.
|
255
253
|
|
256
254
|
Custom Find Strategies
|
257
|
-
|
255
|
+
----------------------
|
258
256
|
|
259
257
|
By default find will search for the document by the id field if the provided id
|
260
258
|
looks like a BSON::ObjectId, and it will otherwise find by the _slugs field. However,
|
@@ -303,6 +301,7 @@ Mongoid::Paranoia Support
|
|
303
301
|
|
304
302
|
The [Mongoid::Paranoia](http://github.com/simi/mongoid-paranoia) gem adds "soft-destroy" functionality to Mongoid documents.
|
305
303
|
Mongoid::Slug contains special handling for Mongoid::Paranoia:
|
304
|
+
|
306
305
|
- When destroying a paranoid document, the slug will be unset from the database.
|
307
306
|
- When restoring a paranoid document, the slug will be rebuilt. Note that the new slug may not match the old one.
|
308
307
|
- When resaving a destroyed paranoid document, the slug will remain unset in the database.
|
@@ -317,17 +316,18 @@ end
|
|
317
316
|
```
|
318
317
|
|
319
318
|
The following variants of Mongoid Paranoia are officially supported:
|
319
|
+
|
320
320
|
* Mongoid 3 built-in Mongoid::Paranoia
|
321
|
-
* Mongoid 4 gem http://github.com/simi/
|
321
|
+
* Mongoid 4 or 5 gem http://github.com/simi/mongoid_paranoia
|
322
|
+
|
323
|
+
|
324
|
+
Contributing
|
325
|
+
------------
|
322
326
|
|
323
|
-
Mongoid
|
324
|
-
is not officially supported but should also work.
|
327
|
+
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.
|
325
328
|
|
329
|
+
Copyright & License
|
330
|
+
-------------------
|
326
331
|
|
327
|
-
|
328
|
-
----------
|
332
|
+
Copyright (c) 2010-2015 Hakan Ensari & Contributors, see [LICENSE](LICENSE) for details.
|
329
333
|
|
330
|
-
[1]: https://github.com/rsl/stringex/
|
331
|
-
[2]: https://secure.travis-ci.org/hakanensari/mongoid-slug.png
|
332
|
-
[3]: http://travis-ci.org/hakanensari/mongoid-slug
|
333
|
-
[4]: https://github.com/digitalplaywright/mongoid-slug/blob/master/lib/mongoid/slug.rb
|
data/lib/mongoid/slug.rb
CHANGED
@@ -5,6 +5,7 @@ require 'mongoid/slug/index'
|
|
5
5
|
require 'mongoid/slug/paranoia'
|
6
6
|
require 'mongoid/slug/unique_slug'
|
7
7
|
require 'mongoid/slug/slug_id_strategy'
|
8
|
+
require 'mongoid-compatibility'
|
8
9
|
|
9
10
|
module Mongoid
|
10
11
|
# Slugs your Mongoid model.
|
@@ -59,8 +60,8 @@ module Mongoid
|
|
59
60
|
options = fields.extract_options!
|
60
61
|
|
61
62
|
self.slug_scope = options[:scope]
|
62
|
-
self.reserved_words = options[:reserve] || Set.new(
|
63
|
-
self.slugged_attributes = fields.map
|
63
|
+
self.reserved_words = options[:reserve] || Set.new(%w(new edit))
|
64
|
+
self.slugged_attributes = fields.map(&:to_s)
|
64
65
|
self.history = options[:history]
|
65
66
|
self.by_model_type = options[:by_model_type]
|
66
67
|
|
@@ -69,7 +70,7 @@ module Mongoid
|
|
69
70
|
|
70
71
|
# Set index
|
71
72
|
unless embedded?
|
72
|
-
index(*Mongoid::Slug::Index.build_index(
|
73
|
+
index(*Mongoid::Slug::Index.build_index(slug_scope_key, by_model_type))
|
73
74
|
end
|
74
75
|
|
75
76
|
#-- Why is it necessary to customize the slug builder?
|
@@ -84,7 +85,7 @@ module Mongoid
|
|
84
85
|
if options[:permanent]
|
85
86
|
set_callback :create, :before, :build_slug
|
86
87
|
else
|
87
|
-
set_callback :save, :before, :build_slug, :
|
88
|
+
set_callback :save, :before, :build_slug, if: :slug_should_be_rebuilt?
|
88
89
|
end
|
89
90
|
|
90
91
|
# If paranoid document:
|
@@ -93,11 +94,11 @@ module Mongoid
|
|
93
94
|
# - recreate the slug on restore
|
94
95
|
# - force reset the slug when saving a destroyed paranoid document, to ensure it stays unset in the database
|
95
96
|
if is_paranoid_doc?
|
96
|
-
|
97
|
+
send(:include, Mongoid::Slug::Paranoia) unless self.respond_to?(:before_restore)
|
97
98
|
set_callback :destroy, :after, :unset_slug!
|
98
99
|
set_callback :restore, :before, :set_slug!
|
99
|
-
set_callback :save, :before, :reset_slug!, :
|
100
|
-
set_callback :save, :after, :clear_slug!, :
|
100
|
+
set_callback :save, :before, :reset_slug!, if: :paranoid_deleted?
|
101
|
+
set_callback :save, :after, :clear_slug!, if: :paranoid_deleted?
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
@@ -109,8 +110,8 @@ module Mongoid
|
|
109
110
|
#
|
110
111
|
# @return [ Array<Document>, Document ] Whether the document is paranoid
|
111
112
|
def slug_scope_key
|
112
|
-
return nil unless
|
113
|
-
|
113
|
+
return nil unless slug_scope
|
114
|
+
reflect_on_association(slug_scope).try(:key) || slug_scope
|
114
115
|
end
|
115
116
|
|
116
117
|
# Find documents by slugs.
|
@@ -135,7 +136,8 @@ module Mongoid
|
|
135
136
|
end
|
136
137
|
|
137
138
|
def queryable
|
138
|
-
|
139
|
+
scope = Mongoid::Compatibility::Version.mongoid5? ? Threaded.current_scope : scope_stack.last
|
140
|
+
scope || Criteria.new(self) # Use Mongoid::Slug::Criteria for slugged documents.
|
139
141
|
end
|
140
142
|
|
141
143
|
# Indicates whether or not the document includes Mongoid::Paranoia
|
@@ -171,19 +173,19 @@ module Mongoid
|
|
171
173
|
end
|
172
174
|
|
173
175
|
def apply_slug
|
174
|
-
|
176
|
+
new_slug = find_unique_slug
|
175
177
|
|
176
|
-
#skip slug generation and use Mongoid id
|
177
|
-
#to find document instead
|
178
|
-
return true if
|
178
|
+
# skip slug generation and use Mongoid id
|
179
|
+
# to find document instead
|
180
|
+
return true if new_slug.size == 0
|
179
181
|
|
180
182
|
# avoid duplicate slugs
|
181
|
-
|
183
|
+
_slugs.delete(new_slug) if _slugs
|
182
184
|
|
183
|
-
if !!
|
184
|
-
append_slug(
|
185
|
+
if !!history && _slugs.is_a?(Array)
|
186
|
+
append_slug(new_slug)
|
185
187
|
else
|
186
|
-
self._slugs = [
|
188
|
+
self._slugs = [new_slug]
|
187
189
|
end
|
188
190
|
end
|
189
191
|
|
@@ -194,7 +196,7 @@ module Mongoid
|
|
194
196
|
# Mongoid 3 (two args) and Mongoid 4 (hash arg)
|
195
197
|
def set_slug!
|
196
198
|
build_slug
|
197
|
-
|
199
|
+
method(:set).arity == 1 ? set(_slugs: _slugs) : set(:_slugs, _slugs)
|
198
200
|
end
|
199
201
|
|
200
202
|
# Atomically unsets the slug field in the database. It is important to unset
|
@@ -228,7 +230,7 @@ module Mongoid
|
|
228
230
|
|
229
231
|
# @return [Boolean] Whether the slug requires to be rebuilt
|
230
232
|
def slug_should_be_rebuilt?
|
231
|
-
(new_record?
|
233
|
+
(new_record? || _slugs_changed? || slugged_attributes_changed?) && !paranoid_deleted?
|
232
234
|
end
|
233
235
|
|
234
236
|
# Indicates whether or not the document has been deleted in paranoid fashion
|
@@ -236,7 +238,7 @@ module Mongoid
|
|
236
238
|
#
|
237
239
|
# @return [Boolean] Whether or not the document has been deleted in paranoid fashion
|
238
240
|
def paranoid_deleted?
|
239
|
-
!!(self.class.is_paranoid_doc?
|
241
|
+
!!(self.class.is_paranoid_doc? && !deleted_at.nil?)
|
240
242
|
end
|
241
243
|
|
242
244
|
def slugged_attributes_changed?
|
@@ -252,17 +254,17 @@ module Mongoid
|
|
252
254
|
# @return [String] the slug, or nil if the document does not have a slug.
|
253
255
|
def slug
|
254
256
|
return _slugs.last if _slugs
|
255
|
-
|
257
|
+
_id.to_s
|
256
258
|
end
|
257
259
|
|
258
260
|
def slug_builder
|
259
|
-
|
260
|
-
if new_with_slugs?
|
261
|
-
#user defined slug
|
262
|
-
|
261
|
+
cur_slug = nil
|
262
|
+
if new_with_slugs? || persisted_with_slug_changes?
|
263
|
+
# user defined slug
|
264
|
+
cur_slug = _slugs.last
|
263
265
|
end
|
264
|
-
#generate slug if the slug is not user defined or does not exist
|
265
|
-
|
266
|
+
# generate slug if the slug is not user defined or does not exist
|
267
|
+
cur_slug || pre_slug_string
|
266
268
|
end
|
267
269
|
|
268
270
|
def self.mongoid3?
|
@@ -271,16 +273,16 @@ module Mongoid
|
|
271
273
|
|
272
274
|
private
|
273
275
|
|
274
|
-
def append_slug(
|
276
|
+
def append_slug(value)
|
275
277
|
if localized?
|
276
278
|
# This is necessary for the scenario in which the slugged locale is not yet present
|
277
279
|
# but the default locale is. In this situation, self._slugs falls back to the default
|
278
280
|
# which is undesired
|
279
|
-
current_slugs =
|
280
|
-
current_slugs <<
|
281
|
-
self._slugs_translations =
|
281
|
+
current_slugs = _slugs_translations.fetch(I18n.locale.to_s, [])
|
282
|
+
current_slugs << value
|
283
|
+
self._slugs_translations = _slugs_translations.merge(I18n.locale.to_s => current_slugs)
|
282
284
|
else
|
283
|
-
|
285
|
+
_slugs << value
|
284
286
|
end
|
285
287
|
end
|
286
288
|
|
@@ -289,29 +291,31 @@ module Mongoid
|
|
289
291
|
if localized?
|
290
292
|
# We need to check if slugs are present for the locale without falling back
|
291
293
|
# to a default
|
292
|
-
new_record?
|
294
|
+
new_record? && _slugs_translations.fetch(I18n.locale.to_s, []).any?
|
293
295
|
else
|
294
|
-
new_record?
|
296
|
+
new_record? && _slugs.present?
|
295
297
|
end
|
296
298
|
end
|
297
299
|
|
298
300
|
# Returns true if object has been persisted and has changes in the slug
|
299
301
|
def persisted_with_slug_changes?
|
300
302
|
if localized?
|
301
|
-
changes =
|
302
|
-
return (persisted?
|
303
|
+
changes = _slugs_change
|
304
|
+
return (persisted? && false) if changes.nil?
|
303
305
|
|
304
306
|
# ensure we check for changes only between the same locale
|
305
307
|
original = changes.first.try(:fetch, I18n.locale.to_s, nil)
|
306
308
|
compare = changes.last.try(:fetch, I18n.locale.to_s, nil)
|
307
|
-
persisted?
|
309
|
+
persisted? && original != compare
|
308
310
|
else
|
309
|
-
persisted?
|
311
|
+
persisted? && _slugs_changed?
|
310
312
|
end
|
311
313
|
end
|
312
314
|
|
313
315
|
def localized?
|
314
|
-
|
316
|
+
fields['_slugs'].options[:localize]
|
317
|
+
rescue
|
318
|
+
false
|
315
319
|
end
|
316
320
|
|
317
321
|
# Return all possible locales for model
|
@@ -319,15 +323,15 @@ module Mongoid
|
|
319
323
|
# doing something crazy, but at the same time we need a fallback in case the model doesn't
|
320
324
|
# have any localized attributes at all (extreme edge case).
|
321
325
|
def all_locales
|
322
|
-
locales =
|
323
|
-
|
324
|
-
|
326
|
+
locales = slugged_attributes
|
327
|
+
.map { |attr| send("#{attr}_translations").keys if self.respond_to?("#{attr}_translations") }
|
328
|
+
.flatten.compact.uniq
|
325
329
|
locales = I18n.available_locales if locales.empty?
|
326
330
|
locales
|
327
331
|
end
|
328
332
|
|
329
333
|
def pre_slug_string
|
330
|
-
|
334
|
+
slugged_attributes.map { |f| send f }.join ' '
|
331
335
|
end
|
332
336
|
end
|
333
337
|
end
|
@@ -60,13 +60,13 @@ module Mongoid
|
|
60
60
|
# unless a :slug_id_strategy option is defined on the id field,
|
61
61
|
# use object_id or string strategy depending on the id_type
|
62
62
|
# otherwise default for all other id_types
|
63
|
-
def build_slug_strategy
|
64
|
-
type_method = id_type.to_s.downcase.split('::').last +
|
65
|
-
self.respond_to?(type_method, true) ? method(type_method) :
|
63
|
+
def build_slug_strategy(id_type)
|
64
|
+
type_method = id_type.to_s.downcase.split('::').last + '_slug_strategy'
|
65
|
+
self.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
|
69
|
-
def objectid_slug_strategy
|
69
|
+
def objectid_slug_strategy(id)
|
70
70
|
if Mongoid::Slug.mongoid3?
|
71
71
|
Moped::BSON::ObjectId.legal? id
|
72
72
|
else
|
@@ -75,20 +75,23 @@ module Mongoid
|
|
75
75
|
end
|
76
76
|
|
77
77
|
# a string will always look like a slug
|
78
|
-
def string_slug_strategy
|
78
|
+
def string_slug_strategy(_id)
|
79
79
|
true
|
80
80
|
end
|
81
81
|
|
82
|
-
|
83
82
|
def for_slugs(slugs)
|
84
|
-
#_translations
|
85
|
-
localized = (
|
83
|
+
# _translations
|
84
|
+
localized = (begin
|
85
|
+
@klass.fields['_slugs'].options[:localize]
|
86
|
+
rescue
|
87
|
+
false
|
88
|
+
end)
|
86
89
|
if localized
|
87
90
|
def_loc = I18n.default_locale
|
88
91
|
query = { '$in' => slugs }
|
89
|
-
where({'$or' => [{ _slugs: query }, { "_slugs.#{def_loc}" => query }]}).limit(slugs.length)
|
92
|
+
where({ '$or' => [{ _slugs: query }, { "_slugs.#{def_loc}" => query }] }).limit(slugs.length)
|
90
93
|
else
|
91
|
-
where(
|
94
|
+
where(_slugs: { '$in' => slugs }).limit(slugs.length)
|
92
95
|
end
|
93
96
|
end
|
94
97
|
|
@@ -102,7 +105,7 @@ module Mongoid
|
|
102
105
|
missing_slugs = slugs - result.map(&:slugs).flatten
|
103
106
|
|
104
107
|
if !missing_slugs.blank? && Mongoid.raise_not_found_error
|
105
|
-
|
108
|
+
fail Errors::DocumentNotFound.new(klass, slugs, missing_slugs)
|
106
109
|
end
|
107
110
|
end
|
108
111
|
end
|
data/lib/mongoid/slug/index.rb
CHANGED
@@ -1,26 +1,23 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Slug
|
3
3
|
module Index
|
4
|
-
|
5
4
|
# @param [ String or Symbol ] scope_key The optional scope key for the index
|
6
5
|
# @param [ Boolean ] by_model_type Whether or not
|
7
6
|
#
|
8
7
|
# @return [ Array(Hash, Hash) ] the indexable fields and index options.
|
9
8
|
def self.build_index(scope_key = nil, by_model_type = false)
|
10
|
-
fields = {_slugs: 1}
|
9
|
+
fields = { _slugs: 1 }
|
11
10
|
options = {}
|
12
11
|
|
13
|
-
if scope_key
|
14
|
-
fields.merge!({scope_key => 1})
|
15
|
-
end
|
12
|
+
fields.merge!(scope_key => 1) if scope_key
|
16
13
|
|
17
14
|
if by_model_type
|
18
|
-
fields.merge!(
|
15
|
+
fields.merge!(_type: 1)
|
19
16
|
else
|
20
|
-
options.merge!(
|
17
|
+
options.merge!(unique: true, sparse: true)
|
21
18
|
end
|
22
19
|
|
23
|
-
|
20
|
+
[fields, options]
|
24
21
|
end
|
25
22
|
end
|
26
23
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Slug
|
3
|
-
|
4
3
|
# Lightweight compatibility shim which adds the :restore callback to
|
5
4
|
# older versions of Mongoid::Paranoia
|
6
5
|
module Paranoia
|
7
6
|
extend ActiveSupport::Concern
|
8
7
|
|
9
8
|
included do
|
10
|
-
|
11
9
|
define_model_callbacks :restore
|
12
10
|
|
13
11
|
def restore_with_callbacks
|
@@ -8,7 +8,7 @@ module Mongoid
|
|
8
8
|
class SlugState
|
9
9
|
attr_reader :last_entered_slug, :existing_slugs, :existing_history_slugs, :sorted_existing
|
10
10
|
|
11
|
-
def initialize
|
11
|
+
def initialize(slug, documents, pattern)
|
12
12
|
@slug = slug
|
13
13
|
@documents = documents
|
14
14
|
@pattern = pattern
|
@@ -21,7 +21,7 @@ module Mongoid
|
|
21
21
|
next if history_slugs.nil?
|
22
22
|
existing_slugs.push(*history_slugs.find_all { |cur_slug| cur_slug =~ @pattern })
|
23
23
|
last_entered_slug.push(*history_slugs.last) if history_slugs.last =~ @pattern
|
24
|
-
existing_history_slugs.push(*history_slugs.first(history_slugs.length
|
24
|
+
existing_history_slugs.push(*history_slugs.first(history_slugs.length - 1).find_all { |cur_slug| cur_slug =~ @pattern })
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -40,19 +40,19 @@ module Mongoid
|
|
40
40
|
|
41
41
|
def sort_existing_slugs
|
42
42
|
# remove the slug part and leave the absolute integer part and sort
|
43
|
-
re =
|
43
|
+
re = /^#{Regexp.escape(@slug)}/
|
44
44
|
@sorted_existing = existing_slugs.map do |s|
|
45
|
-
s.sub(re,'').to_i.abs
|
45
|
+
s.sub(re, '').to_i.abs
|
46
46
|
end.sort
|
47
47
|
end
|
48
48
|
|
49
49
|
def inspect
|
50
50
|
{
|
51
|
-
:
|
52
|
-
:
|
53
|
-
:
|
54
|
-
:
|
55
|
-
:
|
51
|
+
slug: @slug,
|
52
|
+
existing_slugs: existing_slugs,
|
53
|
+
last_entered_slug: last_entered_slug,
|
54
|
+
existing_history_slugs: existing_history_slugs,
|
55
|
+
sorted_existing: sorted_existing
|
56
56
|
}
|
57
57
|
end
|
58
58
|
end
|
@@ -62,12 +62,12 @@ module Mongoid
|
|
62
62
|
attr_reader :model, :_slug
|
63
63
|
|
64
64
|
def_delegators :@model, :slug_scope, :reflect_on_association, :read_attribute,
|
65
|
-
|
66
|
-
|
65
|
+
:check_against_id, :reserved_words, :url_builder, :collection_name,
|
66
|
+
:embedded?, :reflect_on_all_associations, :by_model_type
|
67
67
|
|
68
|
-
def initialize
|
68
|
+
def initialize(model)
|
69
69
|
@model = model
|
70
|
-
@_slug =
|
70
|
+
@_slug = ''
|
71
71
|
@state = nil
|
72
72
|
end
|
73
73
|
|
@@ -75,40 +75,40 @@ module Mongoid
|
|
75
75
|
@model.respond_to?(:relation_metadata) ? @model.relation_metadata : @model.metadata
|
76
76
|
end
|
77
77
|
|
78
|
-
def find_unique
|
78
|
+
def find_unique(attempt = nil)
|
79
79
|
MUTEX_FOR_SLUG.synchronize do
|
80
80
|
@_slug = if attempt
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
attempt.to_url
|
82
|
+
else
|
83
|
+
url_builder.call(model)
|
84
|
+
end
|
85
85
|
# Regular expression that matches slug, slug-1, ... slug-n
|
86
86
|
# If slug_name field was indexed, MongoDB will utilize that
|
87
87
|
# index to match /^.../ pattern.
|
88
88
|
pattern = /^#{Regexp.escape(@_slug)}(?:-(\d+))?$/
|
89
|
-
|
89
|
+
|
90
90
|
where_hash = {}
|
91
91
|
where_hash[:_slugs.all] = [pattern]
|
92
92
|
where_hash[:_id.ne] = model._id
|
93
|
-
|
93
|
+
|
94
94
|
if (scope = slug_scope) && reflect_on_association(scope).nil?
|
95
95
|
# scope is not an association, so it's scoped to a local field
|
96
96
|
# (e.g. an association id in a denormalized db design)
|
97
97
|
where_hash[scope] = model.try(:read_attribute, scope)
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
if by_model_type == true
|
101
101
|
where_hash[:_type] = model.try(:read_attribute, :_type)
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
@state = SlugState.new @_slug, uniqueness_scope.unscoped.where(where_hash), pattern
|
105
|
-
|
105
|
+
|
106
106
|
# do not allow a slug that can be interpreted as the current document id
|
107
107
|
@state.include_slug unless model.class.look_like_slugs?([@_slug])
|
108
|
-
|
108
|
+
|
109
109
|
# make sure that the slug is not equal to a reserved word
|
110
110
|
@state.include_slug if reserved_words.any? { |word| word === @_slug }
|
111
|
-
|
111
|
+
|
112
112
|
# only look for a new unique slug if the existing slugs contains the current slug
|
113
113
|
# - e.g if the slug 'foo-2' is taken, but 'foo' is available, the user can use 'foo'.
|
114
114
|
if @state.slug_included?
|
@@ -120,9 +120,7 @@ module Mongoid
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def uniqueness_scope
|
123
|
-
|
124
|
-
if slug_scope &&
|
125
|
-
metadata = reflect_on_association(slug_scope)
|
123
|
+
if slug_scope && (metadata = reflect_on_association(slug_scope))
|
126
124
|
|
127
125
|
parent = model.send(metadata.name)
|
128
126
|
|
@@ -141,7 +139,7 @@ module Mongoid
|
|
141
139
|
return model._parent.send(parent_metadata.inverse_of || self.metadata.name)
|
142
140
|
end
|
143
141
|
|
144
|
-
#unless embedded or slug scope, return the deepest document superclass
|
142
|
+
# unless embedded or slug scope, return the deepest document superclass
|
145
143
|
appropriate_class = model.class
|
146
144
|
while appropriate_class.superclass.include?(Mongoid::Document)
|
147
145
|
appropriate_class = appropriate_class.superclass
|