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
data/spec/shared/indexes.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
shared_examples
|
1
|
+
shared_examples 'has an index' do |key, options|
|
2
2
|
it "has a #{key} index" do
|
3
3
|
index = if Mongoid::Slug.mongoid3?
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
index.
|
9
|
-
options.each_pair
|
4
|
+
subject.index_options[key]
|
5
|
+
else
|
6
|
+
subject.index_specifications.detect { |spec| spec.key == key }
|
7
|
+
end
|
8
|
+
expect(index).not_to be_nil
|
9
|
+
options.each_pair do |name, value|
|
10
10
|
if Mongoid::Slug.mongoid3?
|
11
|
-
index[name].
|
11
|
+
expect(index[name]).to eq(value)
|
12
12
|
else
|
13
|
-
index.options[name].
|
13
|
+
expect(index.options[name]).to eq(value)
|
14
14
|
end
|
15
|
-
|
15
|
+
end if options
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
shared_examples
|
19
|
+
shared_examples 'does not have an index' do |key, _option|
|
20
20
|
it "does not have the #{key} index" do
|
21
21
|
if Mongoid::Slug.mongoid3?
|
22
|
-
subject.index_options[key].
|
22
|
+
expect(subject.index_options[key]).to be_nil
|
23
23
|
else
|
24
|
-
subject.index_specifications.detect { |spec| spec.key == key }.
|
24
|
+
expect(subject.index_specifications.detect { |spec| spec.key == key }).to be_nil
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
require 'bundler/setup'
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'pry'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
3
|
require 'rspec'
|
8
4
|
require 'uuid'
|
9
5
|
require 'awesome_print'
|
@@ -12,36 +8,44 @@ require 'active_support/deprecation'
|
|
12
8
|
require 'mongoid'
|
13
9
|
require 'mongoid/paranoia'
|
14
10
|
require 'rspec/its'
|
11
|
+
require 'mongoid-compatibility'
|
15
12
|
|
16
13
|
require File.expand_path '../../lib/mongoid/slug', __FILE__
|
17
14
|
|
18
|
-
module Mongoid
|
19
|
-
|
20
|
-
|
15
|
+
module Mongoid
|
16
|
+
module Slug
|
17
|
+
module UuidIdStrategy
|
18
|
+
def self.call(id)
|
19
|
+
id =~ /\A([0-9a-fA-F]){8}-(([0-9a-fA-F]){4}-){3}([0-9a-fA-F]){12}\z/
|
20
|
+
end
|
21
|
+
end
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def database_id
|
25
|
-
|
26
|
+
ENV['CI'] ? "mongoid_slug_#{Process.pid}" : 'mongoid_slug_test'
|
26
27
|
end
|
27
28
|
|
28
29
|
Mongoid.configure do |config|
|
29
30
|
config.connect_to database_id
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
+
%w(models shared).each do |dir|
|
33
34
|
Dir["./spec/#{dir}/*.rb"].each { |f| require f }
|
34
35
|
end
|
35
36
|
|
36
|
-
I18n.available_locales = [
|
37
|
+
I18n.available_locales = [:en, :nl]
|
37
38
|
|
38
39
|
RSpec.configure do |c|
|
40
|
+
c.raise_errors_for_deprecations!
|
41
|
+
|
42
|
+
c.before :all do
|
43
|
+
Mongoid.logger.level = Logger::INFO
|
44
|
+
Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.mongoid5?
|
45
|
+
end
|
46
|
+
|
39
47
|
c.before(:each) do
|
40
48
|
Mongoid.purge!
|
41
49
|
Mongoid::IdentityMap.clear if defined?(Mongoid::IdentityMap)
|
42
50
|
end
|
43
|
-
|
44
|
-
c.after(:suite) do
|
45
|
-
Mongoid::Threaded.sessions[:default].drop if ENV['CI']
|
46
|
-
end
|
47
51
|
end
|
metadata
CHANGED
@@ -1,141 +1,169 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-slug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.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:
|
11
|
+
date: 2015-09-22 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
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongoid-compatibility
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: stringex
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- -
|
45
|
+
- - ~>
|
32
46
|
- !ruby/object:Gem::Version
|
33
47
|
version: '2.0'
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- -
|
52
|
+
- - ~>
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '2.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: guard-rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- -
|
59
|
+
- - ! '>='
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- -
|
66
|
+
- - ! '>='
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- -
|
73
|
+
- - ! '>='
|
60
74
|
- !ruby/object:Gem::Version
|
61
75
|
version: '0'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- -
|
80
|
+
- - ! '>='
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- -
|
87
|
+
- - ! '>='
|
74
88
|
- !ruby/object:Gem::Version
|
75
89
|
version: '0'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- -
|
94
|
+
- - ! '>='
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: rspec-its
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- -
|
101
|
+
- - ! '>='
|
88
102
|
- !ruby/object:Gem::Version
|
89
103
|
version: '0'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- -
|
108
|
+
- - ! '>='
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: awesome_print
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
|
-
- -
|
115
|
+
- - ! '>='
|
102
116
|
- !ruby/object:Gem::Version
|
103
117
|
version: '0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
|
-
- -
|
122
|
+
- - ! '>='
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: uuid
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
|
-
- -
|
129
|
+
- - ! '>='
|
116
130
|
- !ruby/object:Gem::Version
|
117
131
|
version: '0'
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
|
-
- -
|
136
|
+
- - ! '>='
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: pry
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
128
142
|
requirements:
|
129
|
-
- -
|
143
|
+
- - ! '>='
|
130
144
|
- !ruby/object:Gem::Version
|
131
145
|
version: '0'
|
132
146
|
type: :development
|
133
147
|
prerelease: false
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
|
-
- -
|
150
|
+
- - ! '>='
|
137
151
|
- !ruby/object:Gem::Version
|
138
152
|
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.34.2
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 0.34.2
|
139
167
|
description: Mongoid URL slug or permalink generator
|
140
168
|
email:
|
141
169
|
- andy@cosemble.com
|
@@ -182,7 +210,6 @@ files:
|
|
182
210
|
- spec/mongoid/index_spec.rb
|
183
211
|
- spec/mongoid/paranoia_spec.rb
|
184
212
|
- spec/mongoid/slug_spec.rb
|
185
|
-
- spec/mongoid/slug_spec.rb.b00
|
186
213
|
- spec/shared/indexes.rb
|
187
214
|
- spec/spec_helper.rb
|
188
215
|
homepage: https://github.com/digitalplaywright/mongoid-slug
|
@@ -195,17 +222,17 @@ require_paths:
|
|
195
222
|
- lib
|
196
223
|
required_ruby_version: !ruby/object:Gem::Requirement
|
197
224
|
requirements:
|
198
|
-
- -
|
225
|
+
- - ! '>='
|
199
226
|
- !ruby/object:Gem::Version
|
200
227
|
version: '0'
|
201
228
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
229
|
requirements:
|
203
|
-
- -
|
230
|
+
- - ! '>='
|
204
231
|
- !ruby/object:Gem::Version
|
205
232
|
version: '0'
|
206
233
|
requirements: []
|
207
234
|
rubyforge_project: mongoid-slug
|
208
|
-
rubygems_version: 2.
|
235
|
+
rubygems_version: 2.4.5
|
209
236
|
signing_key:
|
210
237
|
specification_version: 4
|
211
238
|
summary: Mongoid URL slugs
|
@@ -239,7 +266,5 @@ test_files:
|
|
239
266
|
- spec/mongoid/index_spec.rb
|
240
267
|
- spec/mongoid/paranoia_spec.rb
|
241
268
|
- spec/mongoid/slug_spec.rb
|
242
|
-
- spec/mongoid/slug_spec.rb.b00
|
243
269
|
- spec/shared/indexes.rb
|
244
270
|
- spec/spec_helper.rb
|
245
|
-
has_rdoc:
|
@@ -1,1101 +0,0 @@
|
|
1
|
-
#encoding: utf-8
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
module Mongoid
|
5
|
-
describe Slug do
|
6
|
-
let(:book) do
|
7
|
-
Book.create(:title => "A Thousand Plateaus")
|
8
|
-
end
|
9
|
-
|
10
|
-
context "should not persist incorrect slugs" do
|
11
|
-
it "slugs should not be generated from invalid documents" do
|
12
|
-
|
13
|
-
#this will fail now
|
14
|
-
x = IncorrectSlugPersistence.create!(name: "test")
|
15
|
-
x.slug.should == 'test'
|
16
|
-
|
17
|
-
#I believe this will now fail
|
18
|
-
x.name = 'te'
|
19
|
-
x.valid?
|
20
|
-
x.slug.should_not == 'te'
|
21
|
-
|
22
|
-
#I believe this will persist the 'te'
|
23
|
-
x.name = 'testb'
|
24
|
-
x.save!
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
context "when option skip_id_check is used with UUID _id " do
|
31
|
-
let(:entity0) do
|
32
|
-
Entity.create(:_id => UUID.generate, :name => 'Pelham 1 2 3', :user_edited_variation => 'pelham-1-2-3')
|
33
|
-
end
|
34
|
-
let(:entity1) do
|
35
|
-
Entity.create(:_id => UUID.generate, :name => 'Jackson 5', :user_edited_variation => 'jackson-5')
|
36
|
-
end
|
37
|
-
let(:entity2) do
|
38
|
-
Entity.create(:_id => UUID.generate, :name => 'Jackson 5', :user_edited_variation => 'jackson-5')
|
39
|
-
end
|
40
|
-
|
41
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
42
|
-
entity0.to_param.should eql "pelham-1-2-3"
|
43
|
-
|
44
|
-
5.times{ |x|
|
45
|
-
dup = Entity.create(:_id => UUID.generate, :name => entity0.name, :user_edited_variation => entity0.user_edited_variation)
|
46
|
-
dup.to_param.should eql "pelham-1-2-3-#{x.succ}"
|
47
|
-
}
|
48
|
-
end
|
49
|
-
|
50
|
-
it "allows the user to edit the sluggable field" do
|
51
|
-
entity1.to_param.should eql "jackson-5"
|
52
|
-
entity2.to_param.should eql "jackson-5-1"
|
53
|
-
entity2.user_edited_variation = "jackson-5-indiana"
|
54
|
-
entity2.save
|
55
|
-
entity2.to_param.should eql "jackson-5-indiana"
|
56
|
-
end
|
57
|
-
|
58
|
-
it "allows users to edit the sluggable field" do
|
59
|
-
entity1.to_param.should eql "jackson-5"
|
60
|
-
entity2.to_param.should eql "jackson-5-1"
|
61
|
-
entity2.user_edited_variation = "jackson-5-indiana"
|
62
|
-
entity2.save
|
63
|
-
entity2.to_param.should eql "jackson-5-indiana"
|
64
|
-
end
|
65
|
-
|
66
|
-
it "it restores the slug if the editing user tries to use an existing slug" do
|
67
|
-
entity1.to_param.should eql "jackson-5"
|
68
|
-
entity2.to_param.should eql "jackson-5-1"
|
69
|
-
entity2.user_edited_variation = "jackson-5"
|
70
|
-
entity2.save
|
71
|
-
entity2.to_param.should eql "jackson-5-1"
|
72
|
-
end
|
73
|
-
|
74
|
-
it "does not force an appended counter on a plain string" do
|
75
|
-
entity = Entity.create(:_id => UUID.generate, :name => 'Adele', :user_edited_variation => 'adele')
|
76
|
-
entity.to_param.should eql "adele"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
context "when the object is top-level" do
|
81
|
-
|
82
|
-
it "generates a slug" do
|
83
|
-
book.to_param.should eql "a-thousand-plateaus"
|
84
|
-
end
|
85
|
-
|
86
|
-
it "updates the slug" do
|
87
|
-
book.title = "Anti Oedipus"
|
88
|
-
book.save
|
89
|
-
book.to_param.should eql "anti-oedipus"
|
90
|
-
end
|
91
|
-
|
92
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
93
|
-
15.times{ |x|
|
94
|
-
dup = Book.create(:title => book.title)
|
95
|
-
dup.to_param.should eql "a-thousand-plateaus-#{x+1}"
|
96
|
-
}
|
97
|
-
end
|
98
|
-
|
99
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
100
|
-
bson_id = Moped::BSON::ObjectId.new.to_s
|
101
|
-
bad = Book.create(:title => bson_id)
|
102
|
-
bad.slugs.should_not include(bson_id)
|
103
|
-
end
|
104
|
-
|
105
|
-
it "does not update slug if slugged fields have not changed" do
|
106
|
-
book.save
|
107
|
-
book.to_param.should eql "a-thousand-plateaus"
|
108
|
-
end
|
109
|
-
|
110
|
-
it "does not change slug if slugged fields have changed but generated slug is identical" do
|
111
|
-
book.title = "a thousand plateaus"
|
112
|
-
book.save
|
113
|
-
book.to_param.should eql "a-thousand-plateaus"
|
114
|
-
end
|
115
|
-
|
116
|
-
context "using find" do
|
117
|
-
it "finds by id as string" do
|
118
|
-
Book.find(book.id.to_s).should eql book
|
119
|
-
end
|
120
|
-
|
121
|
-
it "finds by id as array of strings" do
|
122
|
-
Book.find([book.id.to_s]).should eql [book]
|
123
|
-
end
|
124
|
-
|
125
|
-
it "finds by id as Moped::BSON::ObjectId" do
|
126
|
-
Book.find(book.id).should eql book
|
127
|
-
end
|
128
|
-
|
129
|
-
it "finds by id as an array of Moped::BSON::ObjectIds" do
|
130
|
-
Book.find([book.id]).should eql [book]
|
131
|
-
end
|
132
|
-
|
133
|
-
it "returns an empty array if given an empty array" do
|
134
|
-
Book.find([]).should eql []
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
context "when the object is embedded" do
|
140
|
-
let(:subject) do
|
141
|
-
book.subjects.create(:name => "Psychoanalysis")
|
142
|
-
end
|
143
|
-
|
144
|
-
it "generates a slug" do
|
145
|
-
subject.to_param.should eql "psychoanalysis"
|
146
|
-
end
|
147
|
-
|
148
|
-
it "updates the slug" do
|
149
|
-
subject.name = "Schizoanalysis"
|
150
|
-
subject.save
|
151
|
-
subject.to_param.should eql "schizoanalysis"
|
152
|
-
end
|
153
|
-
|
154
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
155
|
-
dup = book.subjects.create(:name => subject.name)
|
156
|
-
dup.to_param.should eql "psychoanalysis-1"
|
157
|
-
end
|
158
|
-
|
159
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
160
|
-
bad = book.subjects.create(:name => "4ea0389f0364313d79104fb3")
|
161
|
-
bad.slugs.should_not eql "4ea0389f0364313d79104fb3"
|
162
|
-
end
|
163
|
-
|
164
|
-
it "does not update slug if slugged fields have not changed" do
|
165
|
-
subject.save
|
166
|
-
subject.to_param.should eql "psychoanalysis"
|
167
|
-
end
|
168
|
-
|
169
|
-
it "does not change slug if slugged fields have changed but generated slug is identical" do
|
170
|
-
subject.name = "PSYCHOANALYSIS"
|
171
|
-
subject.to_param.should eql "psychoanalysis"
|
172
|
-
end
|
173
|
-
|
174
|
-
context "using find" do
|
175
|
-
it "finds by id as string" do
|
176
|
-
book.subjects.find(subject.id.to_s).should eql subject
|
177
|
-
end
|
178
|
-
|
179
|
-
it "finds by id as array of strings" do
|
180
|
-
book.subjects.find([subject.id.to_s]).should eql [subject]
|
181
|
-
end
|
182
|
-
|
183
|
-
it "finds by id as Moped::BSON::ObjectId" do
|
184
|
-
book.subjects.find(subject.id).should eql subject
|
185
|
-
end
|
186
|
-
|
187
|
-
it "finds by id as an array of Moped::BSON::ObjectIds" do
|
188
|
-
book.subjects.find([subject.id]).should eql [subject]
|
189
|
-
end
|
190
|
-
|
191
|
-
it "returns an empty array if given an empty array" do
|
192
|
-
book.subjects.find([]).should eql []
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
end
|
197
|
-
|
198
|
-
context "when the object is embedded in another embedded object" do
|
199
|
-
let(:person) do
|
200
|
-
Person.create(:name => "John Doe")
|
201
|
-
end
|
202
|
-
|
203
|
-
let(:relationship) do
|
204
|
-
person.relationships.create(:name => "Engagement")
|
205
|
-
end
|
206
|
-
|
207
|
-
let(:partner) do
|
208
|
-
relationship.partners.create(:name => "Jane Smith")
|
209
|
-
end
|
210
|
-
|
211
|
-
it "generates a slug" do
|
212
|
-
partner.to_param.should eql "jane-smith"
|
213
|
-
end
|
214
|
-
|
215
|
-
it "updates the slug" do
|
216
|
-
partner.name = "Jane Doe"
|
217
|
-
partner.save
|
218
|
-
partner.to_param.should eql "jane-doe"
|
219
|
-
end
|
220
|
-
|
221
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
222
|
-
dup = relationship.partners.create(:name => partner.name)
|
223
|
-
dup.to_param.should eql "jane-smith-1"
|
224
|
-
end
|
225
|
-
|
226
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
227
|
-
bad = relationship.partners.create(:name => "4ea0389f0364313d79104fb3")
|
228
|
-
bad.slugs.should_not eql "4ea0389f0364313d79104fb3"
|
229
|
-
end
|
230
|
-
|
231
|
-
it "does not update slug if slugged fields have not changed" do
|
232
|
-
partner.save
|
233
|
-
partner.to_param.should eql "jane-smith"
|
234
|
-
end
|
235
|
-
|
236
|
-
it "does not change slug if slugged fields have changed but generated slug is identical" do
|
237
|
-
partner.name = "JANE SMITH"
|
238
|
-
partner.to_param.should eql "jane-smith"
|
239
|
-
end
|
240
|
-
|
241
|
-
it "scopes by parent object" do
|
242
|
-
affair = person.relationships.create(:name => "Affair")
|
243
|
-
lover = affair.partners.create(:name => partner.name)
|
244
|
-
lover.to_param.should eql partner.to_param
|
245
|
-
end
|
246
|
-
|
247
|
-
context "using find" do
|
248
|
-
it "finds by id as string" do
|
249
|
-
relationship.partners.find(partner.id.to_s).should eql partner
|
250
|
-
end
|
251
|
-
|
252
|
-
it "finds by id as array of strings" do
|
253
|
-
relationship.partners.find([partner.id.to_s]).should eql [partner]
|
254
|
-
end
|
255
|
-
|
256
|
-
it "finds by id as Moped::BSON::ObjectId" do
|
257
|
-
relationship.partners.find(partner.id).should eql partner
|
258
|
-
end
|
259
|
-
|
260
|
-
it "finds by id as an array of Moped::BSON::ObjectIds" do
|
261
|
-
relationship.partners.find([partner.id]).should eql [partner]
|
262
|
-
end
|
263
|
-
|
264
|
-
it "returns an empty array if given an empty array" do
|
265
|
-
relationship.partners.find([]).should eql []
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
end
|
270
|
-
|
271
|
-
context "when the slug is composed of multiple fields" do
|
272
|
-
let!(:author) do
|
273
|
-
Author.create(
|
274
|
-
:first_name => "Gilles",
|
275
|
-
:last_name => "Deleuze")
|
276
|
-
end
|
277
|
-
|
278
|
-
it "generates a slug" do
|
279
|
-
author.to_param.should eql "gilles-deleuze"
|
280
|
-
end
|
281
|
-
|
282
|
-
it "updates the slug" do
|
283
|
-
author.first_name = "Félix"
|
284
|
-
author.last_name = "Guattari"
|
285
|
-
author.save
|
286
|
-
author.to_param.should eql "felix-guattari"
|
287
|
-
end
|
288
|
-
|
289
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
290
|
-
dup = Author.create(
|
291
|
-
:first_name => author.first_name,
|
292
|
-
:last_name => author.last_name)
|
293
|
-
dup.to_param.should eql "gilles-deleuze-1"
|
294
|
-
|
295
|
-
dup2 = Author.create(
|
296
|
-
:first_name => author.first_name,
|
297
|
-
:last_name => author.last_name)
|
298
|
-
|
299
|
-
dup.save
|
300
|
-
dup2.to_param.should eql "gilles-deleuze-2"
|
301
|
-
end
|
302
|
-
|
303
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
304
|
-
bad = Author.create(:first_name => "4ea0389f0364",
|
305
|
-
:last_name => "313d79104fb3")
|
306
|
-
bad.to_param.should_not eql "4ea0389f0364313d79104fb3"
|
307
|
-
end
|
308
|
-
|
309
|
-
it "does not update slug if slugged fields have changed but generated slug is identical" do
|
310
|
-
author.last_name = "DELEUZE"
|
311
|
-
author.save
|
312
|
-
author.to_param.should eql "gilles-deleuze"
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
context "when :as is passed as an argument" do
|
317
|
-
let!(:person) do
|
318
|
-
Person.create(:name => "John Doe")
|
319
|
-
end
|
320
|
-
|
321
|
-
it "sets an alternative slug field name" do
|
322
|
-
person.should respond_to(:_slugs)
|
323
|
-
person.slugs.should eql ["john-doe"]
|
324
|
-
end
|
325
|
-
|
326
|
-
it 'defines #slug' do
|
327
|
-
person.should respond_to :slugs
|
328
|
-
end
|
329
|
-
|
330
|
-
it 'defines #slug_changed?' do
|
331
|
-
person.should respond_to :_slugs_changed?
|
332
|
-
end
|
333
|
-
|
334
|
-
it 'defines #slug_was' do
|
335
|
-
person.should respond_to :_slugs_was
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
context "when :permanent is passed as an argument" do
|
340
|
-
let(:person) do
|
341
|
-
Person.create(:name => "John Doe")
|
342
|
-
end
|
343
|
-
|
344
|
-
it "does not update the slug when the slugged fields change" do
|
345
|
-
person.name = "Jane Doe"
|
346
|
-
person.save
|
347
|
-
person.to_param.should eql "john-doe"
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
context "when :history is passed as an argument" do
|
352
|
-
let(:book) do
|
353
|
-
Book.create(:title => "Book Title")
|
354
|
-
end
|
355
|
-
|
356
|
-
before(:each) do
|
357
|
-
book.title = "Other Book Title"
|
358
|
-
book.save
|
359
|
-
end
|
360
|
-
|
361
|
-
it "saves the old slug in the owner's history" do
|
362
|
-
book.slugs.should include("book-title")
|
363
|
-
end
|
364
|
-
|
365
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
366
|
-
dup = Book.create(:title => "Book Title")
|
367
|
-
dup.to_param.should eql "book-title-1"
|
368
|
-
end
|
369
|
-
|
370
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
371
|
-
bad = Book.create(:title => "4ea0389f0364313d79104fb3")
|
372
|
-
bad.to_param.should_not eql "4ea0389f0364313d79104fb3"
|
373
|
-
end
|
374
|
-
|
375
|
-
it "ensures no duplicate values are stored in history" do
|
376
|
-
book.update_attributes :title => 'Book Title'
|
377
|
-
book.update_attributes :title => 'Foo'
|
378
|
-
book.slugs.find_all { |slug| slug == 'book-title' }.size.should eql 1
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
context "when slug is scoped by a reference association" do
|
383
|
-
let(:author) do
|
384
|
-
book.authors.create(:first_name => "Gilles", :last_name => "Deleuze")
|
385
|
-
end
|
386
|
-
|
387
|
-
it "scopes by parent object" do
|
388
|
-
book2 = Book.create(:title => "Anti Oedipus")
|
389
|
-
dup = book2.authors.create(
|
390
|
-
:first_name => author.first_name,
|
391
|
-
:last_name => author.last_name
|
392
|
-
)
|
393
|
-
dup.to_param.should eql author.to_param
|
394
|
-
end
|
395
|
-
|
396
|
-
it "generates a unique slug by appending a counter to duplicate text" do
|
397
|
-
dup = book.authors.create(
|
398
|
-
:first_name => author.first_name,
|
399
|
-
:last_name => author.last_name)
|
400
|
-
dup.to_param.should eql "gilles-deleuze-1"
|
401
|
-
end
|
402
|
-
|
403
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
404
|
-
bad = book.authors.create(:first_name => "4ea0389f0364",
|
405
|
-
:last_name => "313d79104fb3")
|
406
|
-
bad.to_param.should_not eql "4ea0389f0364313d79104fb3"
|
407
|
-
end
|
408
|
-
|
409
|
-
context "with an irregular association name" do
|
410
|
-
let(:character) do
|
411
|
-
# well we've got to make up something... :-)
|
412
|
-
author.characters.create(:name => "Oedipus")
|
413
|
-
end
|
414
|
-
|
415
|
-
let!(:author2) do
|
416
|
-
Author.create(
|
417
|
-
:first_name => "Sophocles",
|
418
|
-
:last_name => "son of Sophilos"
|
419
|
-
)
|
420
|
-
end
|
421
|
-
|
422
|
-
it "scopes by parent object provided that inverse_of is specified" do
|
423
|
-
dup = author2.characters.create(:name => character.name)
|
424
|
-
dup.to_param.should eql character.to_param
|
425
|
-
end
|
426
|
-
end
|
427
|
-
end
|
428
|
-
|
429
|
-
context "when slug is scoped by one of the class's own fields" do
|
430
|
-
let!(:magazine) do
|
431
|
-
Magazine.create(:title => "Big Weekly", :publisher_id => "abc123")
|
432
|
-
end
|
433
|
-
|
434
|
-
it "should scope by local field" do
|
435
|
-
magazine.to_param.should eql "big-weekly"
|
436
|
-
magazine2 = Magazine.create(:title => "Big Weekly", :publisher_id => "def456")
|
437
|
-
magazine2.to_param.should eql magazine.to_param
|
438
|
-
end
|
439
|
-
|
440
|
-
it "should generate a unique slug by appending a counter to duplicate text" do
|
441
|
-
dup = Magazine.create(:title => "Big Weekly", :publisher_id => "abc123")
|
442
|
-
dup.to_param.should eql "big-weekly-1"
|
443
|
-
end
|
444
|
-
|
445
|
-
it "does not allow a Moped::BSON::ObjectId as use for a slug" do
|
446
|
-
bad = Magazine.create(:title => "4ea0389f0364313d79104fb3", :publisher_id => "abc123")
|
447
|
-
bad.to_param.should_not eql "4ea0389f0364313d79104fb3"
|
448
|
-
end
|
449
|
-
|
450
|
-
end
|
451
|
-
|
452
|
-
context "when #slug is given a block" do
|
453
|
-
let(:caption) do
|
454
|
-
Caption.create(:my_identity => "Edward Hopper (American, 1882-1967)",
|
455
|
-
:title => "Soir Bleu, 1914",
|
456
|
-
:medium => "Oil on Canvas")
|
457
|
-
end
|
458
|
-
|
459
|
-
it "generates a slug" do
|
460
|
-
caption.to_param.should eql "edward-hopper-soir-bleu-1914"
|
461
|
-
end
|
462
|
-
|
463
|
-
it "updates the slug" do
|
464
|
-
caption.title = "Road in Maine, 1914"
|
465
|
-
caption.save
|
466
|
-
caption.to_param.should eql "edward-hopper-road-in-maine-1914"
|
467
|
-
end
|
468
|
-
|
469
|
-
it "does not change slug if slugged fields have changed but generated slug is identical" do
|
470
|
-
caption.my_identity = "Edward Hopper"
|
471
|
-
caption.save
|
472
|
-
caption.to_param.should eql "edward-hopper-soir-bleu-1914"
|
473
|
-
end
|
474
|
-
end
|
475
|
-
|
476
|
-
context "when slugged field contains non-ASCII characters" do
|
477
|
-
it "slugs Cyrillic characters" do
|
478
|
-
book.title = "Капитал"
|
479
|
-
book.save
|
480
|
-
book.to_param.should eql "kapital"
|
481
|
-
end
|
482
|
-
|
483
|
-
it "slugs Greek characters" do
|
484
|
-
book.title = "Ελλάδα"
|
485
|
-
book.save
|
486
|
-
book.to_param.should eql "ellada"
|
487
|
-
end
|
488
|
-
|
489
|
-
it "slugs Chinese characters" do
|
490
|
-
book.title = "中文"
|
491
|
-
book.save
|
492
|
-
book.to_param.should eql "zhong-wen"
|
493
|
-
end
|
494
|
-
|
495
|
-
it "slugs non-ASCII Latin characters" do
|
496
|
-
book.title = "Paul Cézanne"
|
497
|
-
book.save
|
498
|
-
book.to_param.should eql "paul-cezanne"
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
context "when indexes are created" do
|
503
|
-
before do
|
504
|
-
Author.create_indexes
|
505
|
-
Book.create_indexes
|
506
|
-
|
507
|
-
AuthorPolymorphic.create_indexes
|
508
|
-
BookPolymorphic.create_indexes
|
509
|
-
end
|
510
|
-
|
511
|
-
after do
|
512
|
-
Author.remove_indexes
|
513
|
-
Book.remove_indexes
|
514
|
-
|
515
|
-
AuthorPolymorphic.remove_indexes
|
516
|
-
BookPolymorphic.remove_indexes
|
517
|
-
end
|
518
|
-
|
519
|
-
context "when slug is not scoped by a reference association" do
|
520
|
-
it "defines an index on the slug" do
|
521
|
-
Book.index_options.should have_key( :_slugs => 1 )
|
522
|
-
end
|
523
|
-
|
524
|
-
it "defines a unique index" do
|
525
|
-
Book.index_options[ :_slugs => 1 ][:unique].should be_true
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
|
-
context "when slug is scoped by a reference association" do
|
530
|
-
it "does not define an index on the slug" do
|
531
|
-
Author.index_options.should_not have_key(:_slugs => 1 )
|
532
|
-
end
|
533
|
-
end
|
534
|
-
|
535
|
-
context "for subclass scope" do
|
536
|
-
context "when slug is not scoped by a reference association" do
|
537
|
-
it "defines an index on the slug" do
|
538
|
-
BookPolymorphic.index_options.should have_key( :_type => 1, :_slugs => 1 )
|
539
|
-
end
|
540
|
-
|
541
|
-
it "defines a unique index" do
|
542
|
-
BookPolymorphic.index_options[ :_type => 1, :_slugs => 1 ][:unique].should be_true
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
context "when slug is scoped by a reference association" do
|
547
|
-
it "does not define an index on the slug" do
|
548
|
-
AuthorPolymorphic.index_options.should_not have_key(:_type => 1, :_slugs => 1 )
|
549
|
-
end
|
550
|
-
end
|
551
|
-
|
552
|
-
context "when the object has STI" do
|
553
|
-
it "scopes by the subclass" do
|
554
|
-
b = BookPolymorphic.create!(title: 'Book')
|
555
|
-
b.slug.should == 'book'
|
556
|
-
|
557
|
-
b2 = BookPolymorphic.create!(title: 'Book')
|
558
|
-
b2.slug.should == 'book-1'
|
559
|
-
|
560
|
-
c = ComicBookPolymorphic.create!(title: 'Book')
|
561
|
-
c.slug.should == 'book'
|
562
|
-
|
563
|
-
c2 = ComicBookPolymorphic.create!(title: 'Book')
|
564
|
-
c2.slug.should == 'book-1'
|
565
|
-
|
566
|
-
BookPolymorphic.find('book').should == b
|
567
|
-
BookPolymorphic.find('book-1').should == b2
|
568
|
-
ComicBookPolymorphic.find('book').should == c
|
569
|
-
ComicBookPolymorphic.find('book-1').should == c2
|
570
|
-
end
|
571
|
-
end
|
572
|
-
end
|
573
|
-
end
|
574
|
-
|
575
|
-
context "for reserved words" do
|
576
|
-
context "when the :reserve option is used on the model" do
|
577
|
-
it "does not use the reserved slugs" do
|
578
|
-
friend1 = Friend.create(:name => "foo")
|
579
|
-
friend1.slugs.should_not include("foo")
|
580
|
-
friend1.slugs.should include("foo-1")
|
581
|
-
|
582
|
-
friend2 = Friend.create(:name => "bar")
|
583
|
-
friend2.slugs.should_not include("bar")
|
584
|
-
friend2.slugs.should include("bar-1")
|
585
|
-
|
586
|
-
friend3 = Friend.create(:name => "en")
|
587
|
-
friend3.slugs.should_not include("en")
|
588
|
-
friend3.slugs.should include("en-1")
|
589
|
-
end
|
590
|
-
|
591
|
-
it "should start with concatenation -1" do
|
592
|
-
friend1 = Friend.create(:name => "foo")
|
593
|
-
friend1.slugs.should include("foo-1")
|
594
|
-
friend2 = Friend.create(:name => "foo")
|
595
|
-
friend2.slugs.should include("foo-2")
|
596
|
-
end
|
597
|
-
|
598
|
-
["new", "edit"].each do |word|
|
599
|
-
it "should overwrite the default reserved words allowing the word '#{word}'" do
|
600
|
-
friend = Friend.create(:name => word)
|
601
|
-
friend.slugs.should include word
|
602
|
-
end
|
603
|
-
end
|
604
|
-
end
|
605
|
-
context "when the model does not have any reserved words set" do
|
606
|
-
["new", "edit"].each do |word|
|
607
|
-
it "does not use the default reserved word '#{word}'" do
|
608
|
-
book = Book.create(:title => word)
|
609
|
-
book.slugs.should_not include word
|
610
|
-
book.slugs.should include("#{word}-1")
|
611
|
-
end
|
612
|
-
end
|
613
|
-
end
|
614
|
-
end
|
615
|
-
|
616
|
-
context "when the object has STI" do
|
617
|
-
it "scopes by the superclass" do
|
618
|
-
book = Book.create(:title => "Anti Oedipus")
|
619
|
-
comic_book = ComicBook.create(:title => "Anti Oedipus")
|
620
|
-
comic_book.slugs.should_not eql(book.slugs)
|
621
|
-
end
|
622
|
-
|
623
|
-
it "scopes by the subclass" do
|
624
|
-
book = BookPolymorphic.create(:title => "Anti Oedipus")
|
625
|
-
comic_book = ComicBookPolymorphic.create(:title => "Anti Oedipus")
|
626
|
-
comic_book.slugs.should eql(book.slugs)
|
627
|
-
|
628
|
-
BookPolymorphic.find(book.slug).should == book
|
629
|
-
ComicBookPolymorphic.find(comic_book.slug).should == comic_book
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
context "when slug defined on alias of field" do
|
634
|
-
it "should use accessor, not alias" do
|
635
|
-
pseudonim = Alias.create(:author_name => "Max Stirner")
|
636
|
-
pseudonim.slugs.should include("max-stirner")
|
637
|
-
end
|
638
|
-
end
|
639
|
-
|
640
|
-
describe ".find" do
|
641
|
-
let!(:book) { Book.create(:title => "A Working Title").tap { |d| d.update_attribute(:title, "A Thousand Plateaus") } }
|
642
|
-
let!(:book2) { Book.create(:title => "Difference and Repetition") }
|
643
|
-
let!(:friend) { Friend.create(:name => "Jim Bob") }
|
644
|
-
let!(:friend2) { Friend.create(:name => friend.id.to_s) }
|
645
|
-
let!(:integer_id) { IntegerId.new(:name => "I have integer ids").tap { |d| d.id = 123; d.save } }
|
646
|
-
let!(:integer_id2) { IntegerId.new(:name => integer_id.id.to_s).tap { |d| d.id = 456; d.save } }
|
647
|
-
let!(:string_id) { StringId.new(:name => "I have string ids").tap { |d| d.id = 'abc'; d.save } }
|
648
|
-
let!(:string_id2) { StringId.new(:name => string_id.id.to_s).tap { |d| d.id = 'def'; d.save } }
|
649
|
-
let!(:subject) { Subject.create(:title => "A Subject", :book => book) }
|
650
|
-
let!(:subject2) { Subject.create(:title => "A Subject", :book => book2) }
|
651
|
-
let!(:without_slug) { WithoutSlug.new().tap { |d| d.id = 456; d.save } }
|
652
|
-
|
653
|
-
context "when the model does not use mongoid slugs" do
|
654
|
-
it "should not use mongoid slug's custom find methods" do
|
655
|
-
Mongoid::Slug::Criteria.any_instance.should_not_receive(:find)
|
656
|
-
WithoutSlug.find(without_slug.id.to_s).should == without_slug
|
657
|
-
end
|
658
|
-
end
|
659
|
-
|
660
|
-
context "using slugs" do
|
661
|
-
context "(single)" do
|
662
|
-
context "and a document is found" do
|
663
|
-
it "returns the document as an object" do
|
664
|
-
Book.find(book.slugs.first).should == book
|
665
|
-
end
|
666
|
-
end
|
667
|
-
|
668
|
-
context "but no document is found" do
|
669
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
670
|
-
lambda {
|
671
|
-
Book.find("Anti Oedipus")
|
672
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
673
|
-
end
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
677
|
-
context "(multiple)" do
|
678
|
-
context "and all documents are found" do
|
679
|
-
it "returns the documents as an array without duplication" do
|
680
|
-
Book.find(book.slugs + book2.slugs).should =~ [book, book2]
|
681
|
-
end
|
682
|
-
end
|
683
|
-
|
684
|
-
context "but not all documents are found" do
|
685
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
686
|
-
lambda {
|
687
|
-
Book.find(book.slugs + ['something-nonexistent'])
|
688
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
689
|
-
end
|
690
|
-
end
|
691
|
-
end
|
692
|
-
|
693
|
-
context "when no documents match" do
|
694
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
695
|
-
lambda {
|
696
|
-
Book.find("Anti Oedipus")
|
697
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
698
|
-
end
|
699
|
-
end
|
700
|
-
|
701
|
-
context "when ids are BSON::ObjectIds and the supplied argument looks like a BSON::ObjectId" do
|
702
|
-
it "it should find based on ids not slugs" do # i.e. it should type cast the argument
|
703
|
-
Friend.find(friend.id.to_s).should == friend
|
704
|
-
end
|
705
|
-
end
|
706
|
-
|
707
|
-
context "when ids are Strings" do
|
708
|
-
it "it should find based on ids not slugs" do # i.e. string ids should take precedence over string slugs
|
709
|
-
StringId.find(string_id.id.to_s).should == string_id
|
710
|
-
end
|
711
|
-
end
|
712
|
-
|
713
|
-
context "when ids are Integers and the supplied arguments looks like an Integer" do
|
714
|
-
it "it should find based on slugs not ids" do # i.e. it should not type cast the argument
|
715
|
-
IntegerId.find(integer_id.id.to_s).should == integer_id2
|
716
|
-
end
|
717
|
-
end
|
718
|
-
|
719
|
-
context "models that does not use slugs, should find using the original find" do
|
720
|
-
it "it should find based on ids" do # i.e. it should not type cast the argument
|
721
|
-
WithoutSlug.find(without_slug.id.to_s).should == without_slug
|
722
|
-
end
|
723
|
-
end
|
724
|
-
|
725
|
-
context "when scoped" do
|
726
|
-
context "and a document is found" do
|
727
|
-
it "returns the document as an object" do
|
728
|
-
book.subjects.find(subject.slugs.first).should == subject
|
729
|
-
book2.subjects.find(subject.slugs.first).should == subject2
|
730
|
-
end
|
731
|
-
end
|
732
|
-
|
733
|
-
context "but no document is found" do
|
734
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
735
|
-
lambda {
|
736
|
-
book.subjects.find('Another Subject')
|
737
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
738
|
-
end
|
739
|
-
end
|
740
|
-
end
|
741
|
-
end
|
742
|
-
|
743
|
-
context "using ids" do
|
744
|
-
it "raises a Mongoid::Errors::DocumentNotFound error if no document is found" do
|
745
|
-
lambda {
|
746
|
-
Book.find(friend.id)
|
747
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
748
|
-
end
|
749
|
-
|
750
|
-
context "given a single document" do
|
751
|
-
it "returns the document" do
|
752
|
-
Friend.find(friend.id).should == friend
|
753
|
-
end
|
754
|
-
end
|
755
|
-
|
756
|
-
context "given multiple documents" do
|
757
|
-
it "returns the documents" do
|
758
|
-
Book.find([book.id, book2.id]).should =~ [book, book2]
|
759
|
-
end
|
760
|
-
end
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
describe ".find_by_slug!" do
|
765
|
-
let!(:book) { Book.create(:title => "A Working Title").tap { |d| d.update_attribute(:title, "A Thousand Plateaus") } }
|
766
|
-
let!(:book2) { Book.create(:title => "Difference and Repetition") }
|
767
|
-
let!(:friend) { Friend.create(:name => "Jim Bob") }
|
768
|
-
let!(:friend2) { Friend.create(:name => friend.id.to_s) }
|
769
|
-
let!(:integer_id) { IntegerId.new(:name => "I have integer ids").tap { |d| d.id = 123; d.save } }
|
770
|
-
let!(:integer_id2) { IntegerId.new(:name => integer_id.id.to_s).tap { |d| d.id = 456; d.save } }
|
771
|
-
let!(:string_id) { StringId.new(:name => "I have string ids").tap { |d| d.id = 'abc'; d.save } }
|
772
|
-
let!(:string_id2) { StringId.new(:name => string_id.id.to_s).tap { |d| d.id = 'def'; d.save } }
|
773
|
-
let!(:subject) { Subject.create(:title => "A Subject", :book => book) }
|
774
|
-
let!(:subject2) { Subject.create(:title => "A Subject", :book => book2) }
|
775
|
-
|
776
|
-
context "(single)" do
|
777
|
-
context "and a document is found" do
|
778
|
-
it "returns the document as an object" do
|
779
|
-
Book.find_by_slug!(book.slugs.first).should == book
|
780
|
-
end
|
781
|
-
end
|
782
|
-
|
783
|
-
context "but no document is found" do
|
784
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
785
|
-
lambda {
|
786
|
-
Book.find_by_slug!("Anti Oedipus")
|
787
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
788
|
-
end
|
789
|
-
end
|
790
|
-
end
|
791
|
-
|
792
|
-
context "(multiple)" do
|
793
|
-
context "and all documents are found" do
|
794
|
-
it "returns the documents as an array without duplication" do
|
795
|
-
Book.find_by_slug!(book.slugs + book2.slugs).should =~ [book, book2]
|
796
|
-
end
|
797
|
-
end
|
798
|
-
|
799
|
-
context "but not all documents are found" do
|
800
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
801
|
-
lambda {
|
802
|
-
Book.find_by_slug!(book.slugs + ['something-nonexistent'])
|
803
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
804
|
-
end
|
805
|
-
end
|
806
|
-
end
|
807
|
-
|
808
|
-
context "when scoped" do
|
809
|
-
context "and a document is found" do
|
810
|
-
it "returns the document as an object" do
|
811
|
-
book.subjects.find_by_slug!(subject.slugs.first).should == subject
|
812
|
-
book2.subjects.find_by_slug!(subject.slugs.first).should == subject2
|
813
|
-
end
|
814
|
-
end
|
815
|
-
|
816
|
-
context "but no document is found" do
|
817
|
-
it "raises a Mongoid::Errors::DocumentNotFound error" do
|
818
|
-
lambda {
|
819
|
-
book.subjects.find_by_slug!('Another Subject')
|
820
|
-
}.should raise_error(Mongoid::Errors::DocumentNotFound)
|
821
|
-
end
|
822
|
-
end
|
823
|
-
end
|
824
|
-
end
|
825
|
-
|
826
|
-
describe "#to_param" do
|
827
|
-
context "when called on a new record" do
|
828
|
-
let(:book) { Book.new }
|
829
|
-
|
830
|
-
it "should return nil" do
|
831
|
-
book.to_param.should be_nil
|
832
|
-
end
|
833
|
-
|
834
|
-
it "should not persist the record" do
|
835
|
-
book.to_param
|
836
|
-
book.should_not be_persisted
|
837
|
-
end
|
838
|
-
end
|
839
|
-
|
840
|
-
context "when called on an existing record with no slug" do
|
841
|
-
before do
|
842
|
-
Book.collection.insert(:title => "Proust and Signs")
|
843
|
-
end
|
844
|
-
|
845
|
-
it "should return the id" do
|
846
|
-
book = Book.first
|
847
|
-
book.to_param.should == book.id.to_s
|
848
|
-
book.reload.slugs.should be_empty
|
849
|
-
end
|
850
|
-
end
|
851
|
-
end
|
852
|
-
|
853
|
-
describe "#_slugs_changed?" do
|
854
|
-
before do
|
855
|
-
Book.create(:title => "A Thousand Plateaus")
|
856
|
-
end
|
857
|
-
|
858
|
-
let(:book) { Book.first }
|
859
|
-
|
860
|
-
it "is initially unchanged" do
|
861
|
-
book._slugs_changed?.should be_false
|
862
|
-
end
|
863
|
-
|
864
|
-
it "tracks changes" do
|
865
|
-
book.slugs = ["Anti Oedipus"]
|
866
|
-
book._slugs_changed?.should be_true
|
867
|
-
end
|
868
|
-
end
|
869
|
-
|
870
|
-
describe "when regular expression matches, but document does not" do
|
871
|
-
let!(:book_1) { Book.create(:title => "book-1") }
|
872
|
-
let!(:book_2) { Book.create(:title => "book") }
|
873
|
-
let!(:book_3) { Book.create(:title => "book") }
|
874
|
-
|
875
|
-
it "book_2 should have the user supplied title without -1 after it" do
|
876
|
-
book_2.to_param.should eql "book"
|
877
|
-
end
|
878
|
-
|
879
|
-
it "book_3 should have a generated slug" do
|
880
|
-
book_3.to_param.should eql "book-2"
|
881
|
-
end
|
882
|
-
end
|
883
|
-
|
884
|
-
context "when the slugged field is set manually" do
|
885
|
-
context "when it set to a non-empty string" do
|
886
|
-
it "respects the provided slug" do
|
887
|
-
book = Book.create(:title => "A Thousand Plateaus", :slugs => ["not-what-you-expected"])
|
888
|
-
book.to_param.should eql "not-what-you-expected"
|
889
|
-
end
|
890
|
-
|
891
|
-
it "ensures uniqueness" do
|
892
|
-
book1 = Book.create(:title => "A Thousand Plateaus", :slugs => ["not-what-you-expected"])
|
893
|
-
book2 = Book.create(:title => "A Thousand Plateaus", :slugs => ["not-what-you-expected"])
|
894
|
-
book2.to_param.should eql "not-what-you-expected-1"
|
895
|
-
end
|
896
|
-
|
897
|
-
it "updates the slug when a new one is passed in" do
|
898
|
-
book = Book.create(:title => "A Thousand Plateaus", :slugs => ["not-what-you-expected"])
|
899
|
-
book.slugs = ["not-it-either"]
|
900
|
-
book.save
|
901
|
-
book.to_param.should eql "not-it-either"
|
902
|
-
end
|
903
|
-
|
904
|
-
it "updates the slug when a new one is appended" do
|
905
|
-
book = Book.create(:title => "A Thousand Plateaus", :slugs => ["not-what-you-expected"])
|
906
|
-
book.slugs.push "not-it-either"
|
907
|
-
book.save
|
908
|
-
book.to_param.should eql "not-it-either"
|
909
|
-
end
|
910
|
-
|
911
|
-
it "updates the slug to a unique slug when a new one is appended" do
|
912
|
-
book1 = Book.create(:title => "Sleepyhead")
|
913
|
-
book2 = Book.create(:title => "A Thousand Plateaus")
|
914
|
-
book2.slugs.push "sleepyhead"
|
915
|
-
book2.save
|
916
|
-
book2.to_param.should eql "sleepyhead-1"
|
917
|
-
end
|
918
|
-
end
|
919
|
-
|
920
|
-
context "when it is set to an empty string" do
|
921
|
-
it "generate a new one" do
|
922
|
-
book = Book.create(:title => "A Thousand Plateaus")
|
923
|
-
book.to_param.should eql "a-thousand-plateaus"
|
924
|
-
end
|
925
|
-
end
|
926
|
-
end
|
927
|
-
|
928
|
-
context "slug can be localized" do
|
929
|
-
it "generate a new slug for each localization" do
|
930
|
-
old_locale = I18n.locale
|
931
|
-
|
932
|
-
# Using a default locale of en.
|
933
|
-
page = PageSlugLocalize.new
|
934
|
-
page.title = "Title on English"
|
935
|
-
page.save
|
936
|
-
page.slug.should eql "title-on-english"
|
937
|
-
I18n.locale = :nl
|
938
|
-
page.title = "Title on Netherlands"
|
939
|
-
page.save
|
940
|
-
page.slug.should eql "title-on-netherlands"
|
941
|
-
|
942
|
-
# Set locale back to english
|
943
|
-
I18n.locale = old_locale
|
944
|
-
end
|
945
|
-
|
946
|
-
it "returns _id if no slug" do
|
947
|
-
old_locale = I18n.locale
|
948
|
-
|
949
|
-
# Using a default locale of en.
|
950
|
-
page = PageSlugLocalize.new
|
951
|
-
page.title = "Title on English"
|
952
|
-
page.save
|
953
|
-
page.slug.should eql "title-on-english"
|
954
|
-
I18n.locale = :nl
|
955
|
-
page.slug.should eql page._id.to_s
|
956
|
-
|
957
|
-
# Set locale back to english
|
958
|
-
I18n.locale = old_locale
|
959
|
-
end
|
960
|
-
|
961
|
-
it "fallbacks if slug not localized yet" do
|
962
|
-
old_locale = I18n.locale
|
963
|
-
|
964
|
-
# Using a default locale of en.
|
965
|
-
page = PageSlugLocalize.new
|
966
|
-
page.title = "Title on English"
|
967
|
-
page.save
|
968
|
-
page.slug.should eql "title-on-english"
|
969
|
-
I18n.locale = :nl
|
970
|
-
page.slug.should eql page._id.to_s
|
971
|
-
|
972
|
-
# Turn on i18n fallback
|
973
|
-
require "i18n/backend/fallbacks"
|
974
|
-
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
|
975
|
-
::I18n.fallbacks[:nl] = [ :nl, :en ]
|
976
|
-
page.slug.should eql "title-on-english"
|
977
|
-
fallback_slug = page.slug
|
978
|
-
|
979
|
-
fallback_page = PageSlugLocalize.find(fallback_slug) rescue nil
|
980
|
-
fallback_page.should eq(page)
|
981
|
-
|
982
|
-
# Set locale back to english
|
983
|
-
I18n.locale = old_locale
|
984
|
-
|
985
|
-
# Restore fallback for next tests
|
986
|
-
::I18n.fallbacks[:nl] = [ :nl ]
|
987
|
-
end
|
988
|
-
|
989
|
-
it "returns default slug if not localized" do
|
990
|
-
old_locale = I18n.locale
|
991
|
-
|
992
|
-
# Using a default locale of en.
|
993
|
-
page = PageLocalize.new
|
994
|
-
page.title = "Title on English"
|
995
|
-
page.save
|
996
|
-
page.slug.should eql "title-on-english"
|
997
|
-
I18n.locale = :nl
|
998
|
-
page.title = "Title on Netherlands"
|
999
|
-
page.slug.should eql "title-on-english"
|
1000
|
-
page.save
|
1001
|
-
page.slug.should eql "title-on-netherlands"
|
1002
|
-
|
1003
|
-
|
1004
|
-
# Set locale back to english
|
1005
|
-
I18n.locale = old_locale
|
1006
|
-
end
|
1007
|
-
end
|
1008
|
-
|
1009
|
-
context "slug can be localized when using history" do
|
1010
|
-
it "generate a new slug for each localization and keep history" do
|
1011
|
-
old_locale = I18n.locale
|
1012
|
-
|
1013
|
-
# Using a default locale of en.
|
1014
|
-
page = PageSlugLocalizeHistory.new
|
1015
|
-
page.title = "Title on English"
|
1016
|
-
page.save
|
1017
|
-
page.slug.should eql "title-on-english"
|
1018
|
-
I18n.locale = :nl
|
1019
|
-
page.title = "Title on Netherlands"
|
1020
|
-
page.save
|
1021
|
-
page.slug.should eql "title-on-netherlands"
|
1022
|
-
I18n.locale = old_locale
|
1023
|
-
page.title = "Modified title on English"
|
1024
|
-
page.save
|
1025
|
-
page.slug.should eql "modified-title-on-english"
|
1026
|
-
page.slug.should include("title-on-english")
|
1027
|
-
I18n.locale = :nl
|
1028
|
-
page.title = "Modified title on Netherlands"
|
1029
|
-
page.save
|
1030
|
-
page.slug.should eql "modified-title-on-netherlands"
|
1031
|
-
page.slug.should include("title-on-netherlands")
|
1032
|
-
|
1033
|
-
# Set locale back to english
|
1034
|
-
I18n.locale = old_locale
|
1035
|
-
end
|
1036
|
-
|
1037
|
-
it "returns _id if no slug" do
|
1038
|
-
old_locale = I18n.locale
|
1039
|
-
|
1040
|
-
# Using a default locale of en.
|
1041
|
-
page = PageSlugLocalizeHistory.new
|
1042
|
-
page.title = "Title on English"
|
1043
|
-
page.save
|
1044
|
-
page.slug.should eql "title-on-english"
|
1045
|
-
I18n.locale = :nl
|
1046
|
-
page.slug.should eql page._id.to_s
|
1047
|
-
|
1048
|
-
# Set locale back to english
|
1049
|
-
I18n.locale = old_locale
|
1050
|
-
end
|
1051
|
-
|
1052
|
-
it "fallbacks if slug not localized yet" do
|
1053
|
-
old_locale = I18n.locale
|
1054
|
-
|
1055
|
-
# Using a default locale of en.
|
1056
|
-
page = PageSlugLocalizeHistory.new
|
1057
|
-
page.title = "Title on English"
|
1058
|
-
page.save
|
1059
|
-
page.slug.should eql "title-on-english"
|
1060
|
-
I18n.locale = :nl
|
1061
|
-
page.slug.should eql page._id.to_s
|
1062
|
-
|
1063
|
-
# Turn on i18n fallback
|
1064
|
-
require "i18n/backend/fallbacks"
|
1065
|
-
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
|
1066
|
-
::I18n.fallbacks[:nl] = [ :nl, :en ]
|
1067
|
-
page.slug.should eql "title-on-english"
|
1068
|
-
fallback_slug = page.slug
|
1069
|
-
|
1070
|
-
fallback_page = PageSlugLocalizeHistory.find(fallback_slug) rescue nil
|
1071
|
-
fallback_page.should eq(page)
|
1072
|
-
|
1073
|
-
# Set locale back to english
|
1074
|
-
I18n.locale = old_locale
|
1075
|
-
end
|
1076
|
-
end
|
1077
|
-
|
1078
|
-
context "Mongoid paranoia with mongoid slug model" do
|
1079
|
-
|
1080
|
-
let(:paranoid_doc) {ParanoidDocument.create!(:title => "slug")}
|
1081
|
-
|
1082
|
-
it "returns paranoid_doc for correct slug" do
|
1083
|
-
expect(ParanoidDocument.find(paranoid_doc.slug)).to eq(paranoid_doc)
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
it "raises for deleted slug" do
|
1087
|
-
paranoid_doc.delete
|
1088
|
-
expect{ParanoidDocument.find(paranoid_doc.slug)}.to raise_error(Mongoid::Errors::DocumentNotFound)
|
1089
|
-
end
|
1090
|
-
|
1091
|
-
it "returns paranoid_doc for correct restored slug" do
|
1092
|
-
paranoid_doc.delete
|
1093
|
-
ParanoidDocument.deleted.first.restore
|
1094
|
-
expect(ParanoidDocument.find(paranoid_doc.slug)).to eq(paranoid_doc)
|
1095
|
-
end
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
end
|
1100
|
-
end
|
1101
|
-
end
|