mongoid_slug 3.2.1 → 4.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 +4 -4
- data/README.md +31 -1
- data/lib/mongoid/slug.rb +82 -22
- data/lib/mongoid/slug/index.rb +27 -0
- data/lib/mongoid/slug/paranoia.rb +22 -0
- data/lib/mongoid/slug/unique_slug.rb +41 -39
- data/lib/mongoid/slug/version.rb +1 -1
- data/lib/mongoid_slug.rb +1 -5
- data/spec/models/page.rb +1 -1
- data/spec/models/page_localize.rb +1 -1
- data/spec/models/page_slug_localized.rb +1 -1
- data/spec/models/page_slug_localized_history.rb +1 -1
- data/spec/models/paranoid_permanent.rb +8 -0
- data/spec/mongoid/index_spec.rb +34 -0
- data/spec/mongoid/paranoia_spec.rb +169 -0
- data/spec/mongoid/slug_spec.rb +4 -24
- data/spec/spec_helper.rb +10 -4
- metadata +30 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7c5482b8203ac1d0077abb6d57c9b2395a8833c
|
4
|
+
data.tar.gz: 46495e284ce06a65efac3ff1105a8cc5f07042f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbb1ca989496522277f6c1b684df643a621e993b1a9f227de32331c5de15d65dcbfdc049588aadb2fbe1b3cb232f827012265cf4c336e53a128a965b6cf264f8
|
7
|
+
data.tar.gz: e8a8e0a3fce03e2505ee2f9e82d9dea61ddccfa23ffc02195ef2a67d8a8504524a54fd829fbf804e7879606e5ae610e95b1cb68e12190bc3a1a5e40f0222c4c3
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ Installation
|
|
16
16
|
Add to your Gemfile:
|
17
17
|
|
18
18
|
```ruby
|
19
|
-
gem '
|
19
|
+
gem 'mongoid-slug'
|
20
20
|
```
|
21
21
|
|
22
22
|
Usage
|
@@ -297,6 +297,36 @@ unique = Mongoid::Slug::UniqueSlug.new(Book.new).find_unique(title)
|
|
297
297
|
# return some representation of unique
|
298
298
|
```
|
299
299
|
|
300
|
+
|
301
|
+
Mongoid::Paranoia Support
|
302
|
+
-------------------------
|
303
|
+
|
304
|
+
The [Mongoid::Paranoia](http://github.com/simi/mongoid-paranoia) gem adds "soft-destroy" functionality to Mongoid documents.
|
305
|
+
Mongoid::Slug contains special handling for Mongoid::Paranoia:
|
306
|
+
- When destroying a paranoid document, the slug will be unset from the database.
|
307
|
+
- When restoring a paranoid document, the slug will be rebuilt. Note that the new slug may not match the old one.
|
308
|
+
- When resaving a destroyed paranoid document, the slug will remain unset in the database.
|
309
|
+
- 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.
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
class Entity
|
313
|
+
include Mongoid::Document
|
314
|
+
include Mongoid::Slug
|
315
|
+
include Mongoid::Paranoia
|
316
|
+
end
|
317
|
+
```
|
318
|
+
|
319
|
+
The following variants of Mongoid Paranoia are officially supported:
|
320
|
+
* Mongoid 3 built-in Mongoid::Paranoia
|
321
|
+
* Mongoid 4 gem http://github.com/simi/mongoid-paranoia
|
322
|
+
|
323
|
+
Mongoid 4 gem "mongoid-paranoia" (http://github.com/haihappen/mongoid-paranoia)
|
324
|
+
is not officially supported but should also work.
|
325
|
+
|
326
|
+
|
327
|
+
References
|
328
|
+
----------
|
329
|
+
|
300
330
|
[1]: https://github.com/rsl/stringex/
|
301
331
|
[2]: https://secure.travis-ci.org/hakanensari/mongoid-slug.png
|
302
332
|
[3]: http://travis-ci.org/hakanensari/mongoid-slug
|
data/lib/mongoid/slug.rb
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
require 'stringex'
|
3
|
+
require 'mongoid/slug/criteria'
|
4
|
+
require 'mongoid/slug/index'
|
5
|
+
require 'mongoid/slug/paranoia'
|
6
|
+
require 'mongoid/slug/unique_slug'
|
7
|
+
require 'mongoid/slug/slug_id_strategy'
|
8
|
+
|
1
9
|
module Mongoid
|
2
10
|
# Slugs your Mongoid model.
|
3
11
|
module Slug
|
@@ -59,24 +67,9 @@ module Mongoid
|
|
59
67
|
field :_slugs, type: Array, default: [], localize: options[:localize]
|
60
68
|
alias_attribute :slugs, :_slugs
|
61
69
|
|
70
|
+
# Set index
|
62
71
|
unless embedded?
|
63
|
-
|
64
|
-
scope_key = (metadata = self.reflect_on_association(slug_scope)) ? metadata.key : slug_scope
|
65
|
-
if options[:by_model_type] == true
|
66
|
-
# Add _type to the index to fix polymorphism
|
67
|
-
index({ _type: 1, scope_key => 1, _slugs: 1})
|
68
|
-
else
|
69
|
-
index({scope_key => 1, _slugs: 1}, {unique: true, sparse: true})
|
70
|
-
end
|
71
|
-
|
72
|
-
else
|
73
|
-
# Add _type to the index to fix polymorphism
|
74
|
-
if options[:by_model_type] == true
|
75
|
-
index({_type: 1, _slugs: 1})
|
76
|
-
else
|
77
|
-
index({_slugs: 1}, {unique: true, sparse: true})
|
78
|
-
end
|
79
|
-
end
|
72
|
+
index(*Mongoid::Slug::Index.build_index(self.slug_scope_key, self.by_model_type))
|
80
73
|
end
|
81
74
|
|
82
75
|
#-- Why is it necessary to customize the slug builder?
|
@@ -93,12 +86,33 @@ module Mongoid
|
|
93
86
|
else
|
94
87
|
set_callback :save, :before, :build_slug, :if => :slug_should_be_rebuilt?
|
95
88
|
end
|
89
|
+
|
90
|
+
# If paranoid document:
|
91
|
+
# - include shim to add callbacks for restore method
|
92
|
+
# - unset the slugs on destroy
|
93
|
+
# - recreate the slug on restore
|
94
|
+
# - force reset the slug when saving a destroyed paranoid document, to ensure it stays unset in the database
|
95
|
+
if is_paranoid_doc?
|
96
|
+
self.send(:include, Mongoid::Slug::Paranoia) unless self.respond_to?(:before_restore)
|
97
|
+
set_callback :destroy, :after, :unset_slug!
|
98
|
+
set_callback :restore, :before, :set_slug!
|
99
|
+
set_callback :save, :before, :reset_slug!, :if => :paranoid_deleted?
|
100
|
+
set_callback :save, :after, :clear_slug!, :if => :paranoid_deleted?
|
101
|
+
end
|
96
102
|
end
|
97
103
|
|
98
104
|
def look_like_slugs?(*args)
|
99
105
|
with_default_scope.look_like_slugs?(*args)
|
100
106
|
end
|
101
107
|
|
108
|
+
# Returns the scope key for indexing, considering associations
|
109
|
+
#
|
110
|
+
# @return [ Array<Document>, Document ] Whether the document is paranoid
|
111
|
+
def slug_scope_key
|
112
|
+
return nil unless self.slug_scope
|
113
|
+
self.reflect_on_association(self.slug_scope).try(:key) || self.slug_scope
|
114
|
+
end
|
115
|
+
|
102
116
|
# Find documents by slugs.
|
103
117
|
#
|
104
118
|
# A document matches if any of its slugs match one of the supplied params.
|
@@ -124,6 +138,16 @@ module Mongoid
|
|
124
138
|
scope_stack.last || Criteria.new(self) # Use Mongoid::Slug::Criteria for slugged documents.
|
125
139
|
end
|
126
140
|
|
141
|
+
# Indicates whether or not the document includes Mongoid::Paranoia
|
142
|
+
#
|
143
|
+
# This can be replaced with .paranoid? method once the following PRs are merged:
|
144
|
+
# - https://github.com/simi/mongoid-paranoia/pull/19
|
145
|
+
# - https://github.com/haihappen/mongoid-paranoia/pull/3
|
146
|
+
#
|
147
|
+
# @return [ Array<Document>, Document ] Whether the document is paranoid
|
148
|
+
def is_paranoid_doc?
|
149
|
+
!!(defined?(::Mongoid::Paranoia) && self < ::Mongoid::Paranoia)
|
150
|
+
end
|
127
151
|
end
|
128
152
|
|
129
153
|
# Builds a new slug.
|
@@ -135,18 +159,18 @@ module Mongoid
|
|
135
159
|
orig_locale = I18n.locale
|
136
160
|
all_locales.each do |target_locale|
|
137
161
|
I18n.locale = target_locale
|
138
|
-
|
162
|
+
apply_slug
|
139
163
|
end
|
140
164
|
ensure
|
141
165
|
I18n.locale = orig_locale
|
142
166
|
end
|
143
167
|
else
|
144
|
-
|
168
|
+
apply_slug
|
145
169
|
end
|
146
170
|
true
|
147
171
|
end
|
148
172
|
|
149
|
-
def
|
173
|
+
def apply_slug
|
150
174
|
_new_slug = find_unique_slug
|
151
175
|
|
152
176
|
#skip slug generation and use Mongoid id
|
@@ -163,6 +187,35 @@ module Mongoid
|
|
163
187
|
end
|
164
188
|
end
|
165
189
|
|
190
|
+
# Builds slug then atomically sets it in the database.
|
191
|
+
# This is used when working with the Mongoid::Paranoia restore callback.
|
192
|
+
#
|
193
|
+
# This method is adapted to use the :set method variants from both
|
194
|
+
# Mongoid 3 (two args) and Mongoid 4 (hash arg)
|
195
|
+
def set_slug!
|
196
|
+
build_slug
|
197
|
+
self.method(:set).arity == 1 ? set({_slugs: self._slugs}) : set(:_slugs, self._slugs)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Atomically unsets the slug field in the database. It is important to unset
|
201
|
+
# the field for the sparse index on slugs.
|
202
|
+
#
|
203
|
+
# This also resets the in-memory value of the slug field to its default (empty array)
|
204
|
+
def unset_slug!
|
205
|
+
unset(:_slugs)
|
206
|
+
clear_slug!
|
207
|
+
end
|
208
|
+
|
209
|
+
# Rolls back the slug value from the Mongoid changeset.
|
210
|
+
def reset_slug!
|
211
|
+
self.reset__slugs!
|
212
|
+
end
|
213
|
+
|
214
|
+
# Sets the slug to its default value.
|
215
|
+
def clear_slug!
|
216
|
+
self._slugs = []
|
217
|
+
end
|
218
|
+
|
166
219
|
# Finds a unique slug, were specified string used to generate a slug.
|
167
220
|
#
|
168
221
|
# Returned slug will the same as the specified string when there are no
|
@@ -175,7 +228,15 @@ module Mongoid
|
|
175
228
|
|
176
229
|
# @return [Boolean] Whether the slug requires to be rebuilt
|
177
230
|
def slug_should_be_rebuilt?
|
178
|
-
new_record? or _slugs_changed? or slugged_attributes_changed?
|
231
|
+
(new_record? or _slugs_changed? or slugged_attributes_changed?) and !paranoid_deleted?
|
232
|
+
end
|
233
|
+
|
234
|
+
# Indicates whether or not the document has been deleted in paranoid fashion
|
235
|
+
# Always returns false if the document is not paranoid
|
236
|
+
#
|
237
|
+
# @return [Boolean] Whether or not the document has been deleted in paranoid fashion
|
238
|
+
def paranoid_deleted?
|
239
|
+
!!(self.class.is_paranoid_doc? and self.deleted_at != nil)
|
179
240
|
end
|
180
241
|
|
181
242
|
def slugged_attributes_changed?
|
@@ -270,4 +331,3 @@ module Mongoid
|
|
270
331
|
end
|
271
332
|
end
|
272
333
|
end
|
273
|
-
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Slug
|
3
|
+
module Index
|
4
|
+
|
5
|
+
# @param [ String or Symbol ] scope_key The optional scope key for the index
|
6
|
+
# @param [ Boolean ] by_model_type Whether or not
|
7
|
+
#
|
8
|
+
# @return [ Array(Hash, Hash) ] the indexable fields and index options.
|
9
|
+
def self.build_index(scope_key = nil, by_model_type = false)
|
10
|
+
fields = {_slugs: 1}
|
11
|
+
options = {}
|
12
|
+
|
13
|
+
if scope_key
|
14
|
+
fields.merge!({scope_key => 1})
|
15
|
+
end
|
16
|
+
|
17
|
+
if by_model_type
|
18
|
+
fields.merge!({_type: 1})
|
19
|
+
else
|
20
|
+
options.merge!({unique: true, sparse: true})
|
21
|
+
end
|
22
|
+
|
23
|
+
return [fields, options]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Slug
|
3
|
+
|
4
|
+
# Lightweight compatibility shim which adds the :restore callback to
|
5
|
+
# older versions of Mongoid::Paranoia
|
6
|
+
module Paranoia
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
|
11
|
+
define_model_callbacks :restore
|
12
|
+
|
13
|
+
def restore_with_callbacks
|
14
|
+
run_callbacks(:restore) do
|
15
|
+
restore_without_callbacks
|
16
|
+
end
|
17
|
+
end
|
18
|
+
alias_method_chain :restore, :callbacks
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,7 +4,7 @@ require 'forwardable'
|
|
4
4
|
module Mongoid
|
5
5
|
module Slug
|
6
6
|
class UniqueSlug
|
7
|
-
|
7
|
+
MUTEX_FOR_SLUG = Mutex.new
|
8
8
|
class SlugState
|
9
9
|
attr_reader :last_entered_slug, :existing_slugs, :existing_history_slugs, :sorted_existing
|
10
10
|
|
@@ -76,45 +76,47 @@ module Mongoid
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def find_unique attempt = nil
|
79
|
-
|
80
|
-
attempt
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
79
|
+
MUTEX_FOR_SLUG.synchronize do
|
80
|
+
@_slug = if attempt
|
81
|
+
attempt.to_url
|
82
|
+
else
|
83
|
+
url_builder.call(model)
|
84
|
+
end
|
85
|
+
# Regular expression that matches slug, slug-1, ... slug-n
|
86
|
+
# If slug_name field was indexed, MongoDB will utilize that
|
87
|
+
# index to match /^.../ pattern.
|
88
|
+
pattern = /^#{Regexp.escape(@_slug)}(?:-(\d+))?$/
|
89
|
+
|
90
|
+
where_hash = {}
|
91
|
+
where_hash[:_slugs.all] = [pattern]
|
92
|
+
where_hash[:_id.ne] = model._id
|
93
|
+
|
94
|
+
if (scope = slug_scope) && reflect_on_association(scope).nil?
|
95
|
+
# scope is not an association, so it's scoped to a local field
|
96
|
+
# (e.g. an association id in a denormalized db design)
|
97
|
+
where_hash[scope] = model.try(:read_attribute, scope)
|
98
|
+
end
|
99
|
+
|
100
|
+
if by_model_type == true
|
101
|
+
where_hash[:_type] = model.try(:read_attribute, :_type)
|
102
|
+
end
|
103
|
+
|
104
|
+
@state = SlugState.new @_slug, uniqueness_scope.unscoped.where(where_hash), pattern
|
105
|
+
|
106
|
+
# do not allow a slug that can be interpreted as the current document id
|
107
|
+
@state.include_slug unless model.class.look_like_slugs?([@_slug])
|
108
|
+
|
109
|
+
# make sure that the slug is not equal to a reserved word
|
110
|
+
@state.include_slug if reserved_words.any? { |word| word === @_slug }
|
111
|
+
|
112
|
+
# only look for a new unique slug if the existing slugs contains the current slug
|
113
|
+
# - e.g if the slug 'foo-2' is taken, but 'foo' is available, the user can use 'foo'.
|
114
|
+
if @state.slug_included?
|
115
|
+
highest = @state.highest_existing_counter
|
116
|
+
@_slug += "-#{highest.succ}"
|
117
|
+
end
|
118
|
+
@_slug
|
116
119
|
end
|
117
|
-
@_slug
|
118
120
|
end
|
119
121
|
|
120
122
|
def uniqueness_scope
|
data/lib/mongoid/slug/version.rb
CHANGED
data/lib/mongoid_slug.rb
CHANGED
data/spec/models/page.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Mongoid::Slug::Index do
|
5
|
+
|
6
|
+
let(:scope_key) { nil }
|
7
|
+
let(:by_model_type) { false }
|
8
|
+
subject { Mongoid::Slug::Index.build_index(scope_key, by_model_type) }
|
9
|
+
|
10
|
+
context "when scope_key is set" do
|
11
|
+
let(:scope_key) { :foo }
|
12
|
+
|
13
|
+
context "when by_model_type is true" do
|
14
|
+
let(:by_model_type) { true }
|
15
|
+
it { should eq [{:_slugs=>1, :foo=>1, :_type=>1}, {}] }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when by_model_type is false" do
|
19
|
+
it { should eq [{:_slugs=>1, :foo=>1}, {:unique=>true, :sparse=>true}] }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when scope_key is not set" do
|
24
|
+
|
25
|
+
context "when by_model_type is true" do
|
26
|
+
let(:by_model_type) { true }
|
27
|
+
it { should eq [{:_slugs=>1, :_type=>1}, {}] }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when by_model_type is false" do
|
31
|
+
it { should eq [{:_slugs=>1}, {:unique=>true, :sparse=>true}] }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe "Mongoid::Paranoia with Mongoid::Slug" do
|
5
|
+
|
6
|
+
let(:paranoid_doc) { ParanoidDocument.create!(:title => "slug") }
|
7
|
+
let(:paranoid_doc_2) { ParanoidDocument.create!(:title => "slug") }
|
8
|
+
let(:paranoid_perm) { ParanoidPermanent.create!(:title => "slug") }
|
9
|
+
let(:paranoid_perm_2) { ParanoidPermanent.create!(:title => "slug") }
|
10
|
+
let(:non_paranoid_doc){ Article.create!(:title => "slug") }
|
11
|
+
subject{ paranoid_doc }
|
12
|
+
|
13
|
+
describe ".paranoid?" do
|
14
|
+
|
15
|
+
context "when Mongoid::Paranoia is included" do
|
16
|
+
subject { paranoid_doc.class }
|
17
|
+
its(:is_paranoid_doc?){ should be_truthy }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when Mongoid::Paranoia not included" do
|
21
|
+
subject { non_paranoid_doc.class }
|
22
|
+
its(:is_paranoid_doc?){ should be_falsey }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#paranoid_deleted?" do
|
27
|
+
|
28
|
+
context "when Mongoid::Paranoia is included" do
|
29
|
+
|
30
|
+
context "when not destroyed" do
|
31
|
+
its(:paranoid_deleted?){ should be_falsey }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when destroyed" do
|
35
|
+
before { subject.destroy }
|
36
|
+
its(:paranoid_deleted?){ should be_truthy }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when Mongoid::Paranoia not included" do
|
41
|
+
subject { non_paranoid_doc }
|
42
|
+
its(:paranoid_deleted?){ should be_falsey }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "restore callbacks" do
|
47
|
+
|
48
|
+
context "when Mongoid::Paranoia is included" do
|
49
|
+
subject { paranoid_doc.class }
|
50
|
+
it { should respond_to(:before_restore) }
|
51
|
+
it { should respond_to(:after_restore) }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when Mongoid::Paranoia not included" do
|
55
|
+
it { should_not respond_to(:before_restore) }
|
56
|
+
it { should_not respond_to(:after_restore) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "index" do
|
61
|
+
before { ParanoidDocument.create_indexes }
|
62
|
+
after { ParanoidDocument.remove_indexes }
|
63
|
+
subject { ParanoidDocument }
|
64
|
+
|
65
|
+
it_should_behave_like "has an index", { _slugs: 1 }, { unique: true, sparse: true }
|
66
|
+
end
|
67
|
+
|
68
|
+
shared_examples_for "paranoid slugs" do
|
69
|
+
|
70
|
+
context "querying" do
|
71
|
+
|
72
|
+
it "returns paranoid_doc for correct slug" do
|
73
|
+
subject.class.find(subject.slug).should eq(subject)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "delete (callbacks not fired)" do
|
78
|
+
|
79
|
+
before { subject.delete }
|
80
|
+
|
81
|
+
it "retains slug value" do
|
82
|
+
subject.slug.should eq "slug"
|
83
|
+
subject.class.unscoped.find("slug").should eq subject
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "destroy" do
|
88
|
+
|
89
|
+
before { subject.destroy }
|
90
|
+
|
91
|
+
it "unsets slug value when destroyed" do
|
92
|
+
subject._slugs.should eq []
|
93
|
+
subject.slug.should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it "persists the removed slug" do
|
97
|
+
subject.reload._slugs.should eq []
|
98
|
+
subject.reload.slug.should be_nil
|
99
|
+
end
|
100
|
+
|
101
|
+
it "persists the removed slug in the database" do
|
102
|
+
subject.class.unscoped.exists(_slugs: false).first.should eq subject
|
103
|
+
expect{subject.class.unscoped.find("slug")}.to raise_error(Mongoid::Errors::DocumentNotFound)
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when saving the doc again" do
|
107
|
+
|
108
|
+
before { subject.save }
|
109
|
+
|
110
|
+
it "should have the default slug value" do
|
111
|
+
subject._slugs.should eq []
|
112
|
+
subject.slug.should be_nil
|
113
|
+
end
|
114
|
+
|
115
|
+
it "the slug remains unset in the database" do
|
116
|
+
subject.class.unscoped.exists(_slugs: false).first.should eq subject
|
117
|
+
expect{subject.class.unscoped.find("slug")}.to raise_error(Mongoid::Errors::DocumentNotFound)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "restore" do
|
123
|
+
|
124
|
+
before do
|
125
|
+
subject.destroy
|
126
|
+
subject.restore
|
127
|
+
end
|
128
|
+
|
129
|
+
it "resets slug value when restored" do
|
130
|
+
subject.slug.should eq "slug"
|
131
|
+
subject.reload.slug.should eq "slug"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "multiple documents" do
|
136
|
+
|
137
|
+
it "new documents should be able to use the slug of destroyed documents" do
|
138
|
+
subject.slug.should eq "slug"
|
139
|
+
subject.destroy
|
140
|
+
subject.reload.slug.should be_nil
|
141
|
+
other_doc.slug.should eq "slug"
|
142
|
+
subject.restore
|
143
|
+
subject.slug.should eq "slug-1"
|
144
|
+
subject.reload.slug.should eq "slug-1"
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should allow multiple documents to be destroyed without index conflict" do
|
148
|
+
subject.slug.should eq "slug"
|
149
|
+
subject.destroy
|
150
|
+
subject.reload.slug.should be_nil
|
151
|
+
other_doc.slug.should eq "slug"
|
152
|
+
other_doc.destroy
|
153
|
+
other_doc.reload.slug.should be_nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "non-permanent slug" do
|
159
|
+
subject { paranoid_doc }
|
160
|
+
let(:other_doc) { paranoid_doc_2 }
|
161
|
+
it_behaves_like "paranoid slugs"
|
162
|
+
end
|
163
|
+
|
164
|
+
context "permanent slug" do
|
165
|
+
subject { paranoid_perm }
|
166
|
+
let(:other_doc) { paranoid_perm_2 }
|
167
|
+
it_behaves_like "paranoid slugs"
|
168
|
+
end
|
169
|
+
end
|
data/spec/mongoid/slug_spec.rb
CHANGED
@@ -523,7 +523,7 @@ module Mongoid
|
|
523
523
|
|
524
524
|
context "when slug is not scoped by a reference association" do
|
525
525
|
subject { Book }
|
526
|
-
it_should_behave_like "has an index", { _slugs: 1 }, { unique: true }
|
526
|
+
it_should_behave_like "has an index", { _slugs: 1 }, { unique: true, sparse: true }
|
527
527
|
end
|
528
528
|
|
529
529
|
context "when slug is scoped by a reference association" do
|
@@ -534,7 +534,7 @@ module Mongoid
|
|
534
534
|
context "for subclass scope" do
|
535
535
|
context "when slug is not scoped by a reference association" do
|
536
536
|
subject { BookPolymorphic }
|
537
|
-
it_should_behave_like "has an index", { _type: 1, _slugs: 1 }, { unique: nil }
|
537
|
+
it_should_behave_like "has an index", { _type: 1, _slugs: 1 }, { unique: nil, sparse: nil }
|
538
538
|
end
|
539
539
|
|
540
540
|
context "when slug is scoped by a reference association" do
|
@@ -672,12 +672,12 @@ module Mongoid
|
|
672
672
|
let(:book) { Book.first }
|
673
673
|
|
674
674
|
it "is initially unchanged" do
|
675
|
-
book._slugs_changed?.should
|
675
|
+
book._slugs_changed?.should be_falsey
|
676
676
|
end
|
677
677
|
|
678
678
|
it "tracks changes" do
|
679
679
|
book.slugs = ["Anti Oedipus"]
|
680
|
-
book._slugs_changed?.should
|
680
|
+
book._slugs_changed?.should be_truthy
|
681
681
|
end
|
682
682
|
end
|
683
683
|
|
@@ -1018,25 +1018,5 @@ module Mongoid
|
|
1018
1018
|
end
|
1019
1019
|
|
1020
1020
|
end
|
1021
|
-
|
1022
|
-
context "Mongoid paranoia with mongoid slug model" do
|
1023
|
-
|
1024
|
-
let(:paranoid_doc) {ParanoidDocument.create!(:title => "slug")}
|
1025
|
-
|
1026
|
-
it "returns paranoid_doc for correct slug" do
|
1027
|
-
ParanoidDocument.find(paranoid_doc.slug).should eq(paranoid_doc)
|
1028
|
-
end
|
1029
|
-
|
1030
|
-
it "raises for deleted slug" do
|
1031
|
-
paranoid_doc.delete
|
1032
|
-
expect{ParanoidDocument.find(paranoid_doc.slug)}.to raise_error(Mongoid::Errors::DocumentNotFound)
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
it "returns paranoid_doc for correct restored slug" do
|
1036
|
-
paranoid_doc.delete
|
1037
|
-
ParanoidDocument.deleted.first.restore
|
1038
|
-
ParanoidDocument.find(paranoid_doc.slug).should eq(paranoid_doc)
|
1039
|
-
end
|
1040
|
-
end
|
1041
1021
|
end
|
1042
1022
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'pry'
|
3
5
|
rescue LoadError
|
4
6
|
end
|
5
7
|
require 'rspec'
|
6
8
|
require 'uuid'
|
7
|
-
require
|
8
|
-
|
9
|
-
require
|
9
|
+
require 'awesome_print'
|
10
|
+
require 'active_support'
|
11
|
+
require 'active_support/deprecation'
|
12
|
+
require 'mongoid'
|
10
13
|
require 'mongoid/paranoia'
|
14
|
+
require 'rspec/its'
|
15
|
+
|
16
|
+
require File.expand_path '../../lib/mongoid/slug', __FILE__
|
11
17
|
|
12
18
|
module Mongoid::Slug::UuidIdStrategy
|
13
19
|
def self.call id
|
@@ -32,7 +38,7 @@ I18n.available_locales = [ :en, :nl ]
|
|
32
38
|
RSpec.configure do |c|
|
33
39
|
c.before(:each) do
|
34
40
|
Mongoid.purge!
|
35
|
-
Mongoid::IdentityMap.clear
|
41
|
+
Mongoid::IdentityMap.clear if defined?(Mongoid::IdentityMap)
|
36
42
|
end
|
37
43
|
|
38
44
|
c.after(:suite) do
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_slug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Saebjoernsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongoid
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-its
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: awesome_print
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,6 +147,8 @@ files:
|
|
133
147
|
- README.md
|
134
148
|
- lib/mongoid/slug.rb
|
135
149
|
- lib/mongoid/slug/criteria.rb
|
150
|
+
- lib/mongoid/slug/index.rb
|
151
|
+
- lib/mongoid/slug/paranoia.rb
|
136
152
|
- lib/mongoid/slug/slug_id_strategy.rb
|
137
153
|
- lib/mongoid/slug/unique_slug.rb
|
138
154
|
- lib/mongoid/slug/version.rb
|
@@ -155,6 +171,7 @@ files:
|
|
155
171
|
- spec/models/page_slug_localized_custom.rb
|
156
172
|
- spec/models/page_slug_localized_history.rb
|
157
173
|
- spec/models/paranoid_document.rb
|
174
|
+
- spec/models/paranoid_permanent.rb
|
158
175
|
- spec/models/partner.rb
|
159
176
|
- spec/models/person.rb
|
160
177
|
- spec/models/relationship.rb
|
@@ -162,6 +179,8 @@ files:
|
|
162
179
|
- spec/models/subject.rb
|
163
180
|
- spec/models/without_slug.rb
|
164
181
|
- spec/mongoid/criteria_spec.rb
|
182
|
+
- spec/mongoid/index_spec.rb
|
183
|
+
- spec/mongoid/paranoia_spec.rb
|
165
184
|
- spec/mongoid/slug_spec.rb
|
166
185
|
- spec/mongoid/slug_spec.rb.b00
|
167
186
|
- spec/shared/indexes.rb
|
@@ -170,7 +189,9 @@ homepage: https://github.com/digitalplaywright/mongoid-slug
|
|
170
189
|
licenses:
|
171
190
|
- MIT
|
172
191
|
metadata: {}
|
173
|
-
post_install_message:
|
192
|
+
post_install_message: "[NOTICE]: Deprecated gem name. The name of this gem will be
|
193
|
+
changing from 'mongoid_slug' to 'mongoid-slug' (notice the hyphen). To ensure you
|
194
|
+
are using the correct version of this gem, please use 'mongoid-slug'."
|
174
195
|
rdoc_options: []
|
175
196
|
require_paths:
|
176
197
|
- lib
|
@@ -209,6 +230,7 @@ test_files:
|
|
209
230
|
- spec/models/page_slug_localized_custom.rb
|
210
231
|
- spec/models/page_slug_localized_history.rb
|
211
232
|
- spec/models/paranoid_document.rb
|
233
|
+
- spec/models/paranoid_permanent.rb
|
212
234
|
- spec/models/partner.rb
|
213
235
|
- spec/models/person.rb
|
214
236
|
- spec/models/relationship.rb
|
@@ -216,7 +238,10 @@ test_files:
|
|
216
238
|
- spec/models/subject.rb
|
217
239
|
- spec/models/without_slug.rb
|
218
240
|
- spec/mongoid/criteria_spec.rb
|
241
|
+
- spec/mongoid/index_spec.rb
|
242
|
+
- spec/mongoid/paranoia_spec.rb
|
219
243
|
- spec/mongoid/slug_spec.rb
|
220
244
|
- spec/mongoid/slug_spec.rb.b00
|
221
245
|
- spec/shared/indexes.rb
|
222
246
|
- spec/spec_helper.rb
|
247
|
+
has_rdoc:
|