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