mongoid-slug 6.0.0 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +20 -20
  3. data/README.md +361 -336
  4. data/lib/mongoid/slug.rb +328 -328
  5. data/lib/mongoid/slug/criteria.rb +107 -107
  6. data/lib/mongoid/slug/{index.rb → index_builder.rb} +67 -45
  7. data/lib/mongoid/slug/railtie.rb +9 -9
  8. data/lib/mongoid/slug/slug_id_strategy.rb +3 -3
  9. data/lib/mongoid/slug/unique_slug.rb +173 -173
  10. data/lib/mongoid/slug/version.rb +5 -5
  11. data/lib/mongoid_slug.rb +2 -2
  12. data/lib/tasks/mongoid_slug.rake +15 -19
  13. data/spec/models/alias.rb +6 -6
  14. data/spec/models/article.rb +9 -9
  15. data/spec/models/artist.rb +8 -8
  16. data/spec/models/artwork.rb +10 -10
  17. data/spec/models/author.rb +15 -15
  18. data/spec/models/author_polymorphic.rb +15 -15
  19. data/spec/models/book.rb +12 -12
  20. data/spec/models/book_polymorphic.rb +12 -12
  21. data/spec/models/caption.rb +17 -17
  22. data/spec/models/entity.rb +11 -11
  23. data/spec/models/friend.rb +7 -7
  24. data/spec/models/incorrect_slug_persistence.rb +9 -9
  25. data/spec/models/integer_id.rb +9 -9
  26. data/spec/models/magazine.rb +7 -7
  27. data/spec/models/page.rb +9 -9
  28. data/spec/models/page_localize.rb +9 -9
  29. data/spec/models/page_slug_localized.rb +9 -9
  30. data/spec/models/page_slug_localized_custom.rb +10 -10
  31. data/spec/models/page_slug_localized_history.rb +9 -9
  32. data/spec/models/partner.rb +7 -7
  33. data/spec/models/person.rb +12 -12
  34. data/spec/models/relationship.rb +8 -8
  35. data/spec/models/string_id.rb +9 -9
  36. data/spec/models/subject.rb +7 -7
  37. data/spec/models/without_slug.rb +5 -5
  38. data/spec/mongoid/criteria_spec.rb +207 -207
  39. data/spec/mongoid/index_builder_spec.rb +105 -0
  40. data/spec/mongoid/slug_spec.rb +1175 -1169
  41. data/spec/shared/indexes.rb +41 -41
  42. data/spec/spec_helper.rb +61 -61
  43. data/spec/tasks/mongoid_slug_rake_spec.rb +73 -73
  44. metadata +31 -32
  45. data/spec/mongoid/index_spec.rb +0 -33
@@ -1,9 +1,9 @@
1
- class PageSlugLocalizedHistory
2
- include Mongoid::Document
3
- include Mongoid::Slug
4
- field :title, localize: true
5
- field :content
6
- field :order, type: Integer
7
- slug :title, localize: true, history: true
8
- default_scope -> { asc(:order) }
9
- end
1
+ class PageSlugLocalizedHistory
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+ field :title, localize: true
5
+ field :content
6
+ field :order, type: Integer
7
+ slug :title, localize: true, history: true
8
+ default_scope -> { asc(:order) }
9
+ end
@@ -1,7 +1,7 @@
1
- class Partner
2
- include Mongoid::Document
3
- include Mongoid::Slug
4
- field :name
5
- slug :name
6
- embedded_in :relationship
7
- end
1
+ class Partner
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+ field :name
5
+ slug :name
6
+ embedded_in :relationship
7
+ end
@@ -1,12 +1,12 @@
1
- class Person
2
- include Mongoid::Document
3
- include Mongoid::Slug
4
- field :name
5
- slug :name, permanent: true, scope: :author
6
- embeds_many :relationships
7
- if Mongoid::Compatibility::Version.mongoid6_or_newer?
8
- belongs_to :author, inverse_of: :characters, required: false
9
- else
10
- belongs_to :author, inverse_of: :characters
11
- end
12
- end
1
+ class Person
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+ field :name
5
+ slug :name, permanent: true, scope: :author
6
+ embeds_many :relationships
7
+ if Mongoid::Compatibility::Version.mongoid6_or_newer?
8
+ belongs_to :author, inverse_of: :characters, required: false
9
+ else
10
+ belongs_to :author, inverse_of: :characters
11
+ end
12
+ end
@@ -1,8 +1,8 @@
1
- class Relationship
2
- include Mongoid::Document
3
- include Mongoid::Slug
4
- field :name
5
- slug :name
6
- embeds_many :partners
7
- embedded_in :person
8
- end
1
+ class Relationship
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+ field :name
5
+ slug :name
6
+ embeds_many :partners
7
+ embedded_in :person
8
+ end
@@ -1,9 +1,9 @@
1
- class StringId
2
- include Mongoid::Document
3
- include Mongoid::Slug
4
-
5
- field :_id, type: String
6
- field :name, type: String
7
-
8
- slug :name, history: true
9
- end
1
+ class StringId
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+
5
+ field :_id, type: String
6
+ field :name, type: String
7
+
8
+ slug :name, history: true
9
+ end
@@ -1,7 +1,7 @@
1
- class Subject
2
- include Mongoid::Document
3
- include Mongoid::Slug
4
- field :name
5
- slug :name, scope: :book, history: true
6
- embedded_in :book
7
- end
1
+ class Subject
2
+ include Mongoid::Document
3
+ include Mongoid::Slug
4
+ field :name
5
+ slug :name, scope: :book, history: true
6
+ embedded_in :book
7
+ end
@@ -1,5 +1,5 @@
1
- class WithoutSlug
2
- include Mongoid::Document
3
-
4
- field :_id, type: Integer
5
- end
1
+ class WithoutSlug
2
+ include Mongoid::Document
3
+
4
+ field :_id, type: Integer
5
+ end
@@ -1,207 +1,207 @@
1
- require 'spec_helper'
2
-
3
- describe Mongoid::Slug::Criteria do
4
- describe '.find' do
5
- let!(:book) { Book.create(title: 'A Working Title').tap { |d| d.update_attribute(:title, 'A Thousand Plateaus') } }
6
- let!(:book2) { Book.create(title: 'Difference and Repetition') }
7
- let!(:friend) { Friend.create(name: 'Jim Bob') }
8
- let!(:friend2) { Friend.create(name: friend.id.to_s) }
9
- let!(:integer_id) { IntegerId.new(name: 'I have integer ids').tap { |d| d.id = 123; d.save! } }
10
- let!(:integer_id2) { IntegerId.new(name: integer_id.id.to_s).tap { |d| d.id = 456; d.save! } }
11
- let!(:string_id) { StringId.new(name: 'I have string ids').tap { |d| d.id = 'abc'; d.save! } }
12
- let!(:string_id2) { StringId.new(name: string_id.id.to_s).tap { |d| d.id = 'def'; d.save! } }
13
- let!(:subject) { Subject.create(name: 'A Subject', book: book) }
14
- let!(:subject2) { Subject.create(name: 'A Subject', book: book2) }
15
- let!(:without_slug) { WithoutSlug.new.tap { |d| d.id = 456; d.save! } }
16
-
17
- context 'when the model does not use mongoid slugs' do
18
- it "should not use mongoid slug's custom find methods" do
19
- expect_any_instance_of(Mongoid::Slug::Criteria).not_to receive(:find)
20
- expect(WithoutSlug.find(without_slug.id.to_s)).to eq(without_slug)
21
- end
22
- end
23
-
24
- context 'using slugs' do
25
- context '(single)' do
26
- context 'and a document is found' do
27
- it 'returns the document as an object' do
28
- expect(Book.find(book.slugs.first)).to eq(book)
29
- end
30
- end
31
-
32
- context 'but no document is found' do
33
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
34
- expect do
35
- Book.find('Anti Oedipus')
36
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
37
- end
38
- end
39
- end
40
-
41
- context '(multiple)' do
42
- context 'and all documents are found' do
43
- it 'returns the documents as an array without duplication' do
44
- expect(Book.find(book.slugs + book2.slugs)).to match_array([book, book2])
45
- end
46
- end
47
-
48
- context 'but not all documents are found' do
49
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
50
- expect do
51
- Book.find(book.slugs + ['something-nonexistent'])
52
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
53
- end
54
- end
55
- end
56
-
57
- context 'when no documents match' do
58
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
59
- expect do
60
- Book.find('Anti Oedipus')
61
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
62
- end
63
- end
64
-
65
- context 'when ids are BSON::ObjectIds and the supplied argument looks like a BSON::ObjectId' do
66
- it 'it should find based on ids not slugs' do # i.e. it should type cast the argument
67
- expect(Friend.find(friend.id.to_s)).to eq(friend)
68
- end
69
- end
70
-
71
- context 'when ids are Strings' do
72
- it 'it should find based on ids not slugs' do # i.e. string ids should take precedence over string slugs
73
- expect(StringId.find(string_id.id.to_s)).to eq(string_id)
74
- end
75
- end
76
-
77
- context 'when ids are Integers and the supplied arguments looks like an Integer' do
78
- it 'it should find based on slugs not ids' do # i.e. it should not type cast the argument
79
- expect(IntegerId.find(integer_id.id.to_s)).to eq(integer_id2)
80
- end
81
- end
82
-
83
- context 'models that does not use slugs, should find using the original find' do
84
- it 'it should find based on ids' do # i.e. it should not type cast the argument
85
- expect(WithoutSlug.find(without_slug.id.to_s)).to eq(without_slug)
86
- end
87
- end
88
-
89
- context 'when scoped' do
90
- context 'and a document is found' do
91
- it 'returns the document as an object' do
92
- expect(book.subjects.find(subject.slugs.first)).to eq(subject)
93
- expect(book2.subjects.find(subject.slugs.first)).to eq(subject2)
94
- end
95
- end
96
-
97
- context 'but no document is found' do
98
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
99
- expect do
100
- book.subjects.find('Another Subject')
101
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
102
- end
103
- end
104
- end
105
- end
106
-
107
- context 'using ids' do
108
- it 'raises a Mongoid::Errors::DocumentNotFound error if no document is found' do
109
- expect do
110
- Book.find(friend.id)
111
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
112
- end
113
-
114
- context 'given a single document' do
115
- it 'returns the document' do
116
- expect(Friend.find(friend.id)).to eq(friend)
117
- end
118
- end
119
-
120
- context 'given multiple documents' do
121
- it 'returns the documents' do
122
- expect(Book.find([book.id, book2.id])).to match_array([book, book2])
123
- end
124
- end
125
- end
126
- end
127
-
128
- describe '.find_by_slug!' do
129
- let!(:book) { Book.create(title: 'A Working Title').tap { |d| d.update_attribute(:title, 'A Thousand Plateaus') } }
130
- let!(:book2) { Book.create(title: 'Difference and Repetition') }
131
- let!(:friend) { Friend.create(name: 'Jim Bob') }
132
- let!(:friend2) { Friend.create(name: friend.id.to_s) }
133
- let!(:integer_id) { IntegerId.new(name: 'I have integer ids').tap { |d| d.id = 123; d.save! } }
134
- let!(:integer_id2) { IntegerId.new(name: integer_id.id.to_s).tap { |d| d.id = 456; d.save! } }
135
- let!(:string_id) { StringId.new(name: 'I have string ids').tap { |d| d.id = 'abc'; d.save! } }
136
- let!(:string_id2) { StringId.new(name: string_id.id.to_s).tap { |d| d.id = 'def'; d.save! } }
137
- let!(:subject) { Subject.create(name: 'A Subject', book: book) }
138
- let!(:subject2) { Subject.create(name: 'A Subject', book: book2) }
139
-
140
- context '(single)' do
141
- context 'and a document is found' do
142
- it 'returns the document as an object' do
143
- expect(Book.find_by_slug!(book.slugs.first)).to eq(book)
144
- end
145
- end
146
-
147
- context 'but no document is found' do
148
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
149
- expect do
150
- Book.find_by_slug!('Anti Oedipus')
151
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
152
- end
153
- end
154
- end
155
-
156
- context '(multiple)' do
157
- context 'and all documents are found' do
158
- it 'returns the documents as an array without duplication' do
159
- expect(Book.find_by_slug!(book.slugs + book2.slugs)).to match_array([book, book2])
160
- end
161
- end
162
-
163
- context 'but not all documents are found' do
164
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
165
- expect do
166
- Book.find_by_slug!(book.slugs + ['something-nonexistent'])
167
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
168
- end
169
- end
170
- end
171
-
172
- context 'when scoped' do
173
- context 'and a document is found' do
174
- it 'returns the document as an object' do
175
- expect(book.subjects.find_by_slug!(subject.slugs.first)).to eq(subject)
176
- expect(book2.subjects.find_by_slug!(subject.slugs.first)).to eq(subject2)
177
- end
178
- end
179
-
180
- context 'but no document is found' do
181
- it 'raises a Mongoid::Errors::DocumentNotFound error' do
182
- expect do
183
- book.subjects.find_by_slug!('Another Subject')
184
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
185
- end
186
- end
187
- end
188
- end
189
-
190
- describe '.where' do
191
- let!(:artist1) { Artist.create!(name: 'Leonardo') }
192
- let!(:artist2) { Artist.create!(name: 'Malevich') }
193
- let!(:artwork1) { Artwork.create!(title: 'Mona Lisa', artist_ids: [artist1.id], published: true) }
194
- let!(:artwork2) { Artwork.create!(title: 'Black Square', artist_ids: [artist2.id], published: false) }
195
- let!(:artwork3) { Artwork.create! }
196
-
197
- it 'counts artworks' do
198
- expect(Artwork.in(artist_ids: artist1.id).count).to eq 1
199
- expect(Artwork.in(artist_ids: artist2.id).count).to eq 1
200
- end
201
-
202
- it 'counts published artworks' do
203
- expect(Artwork.in(artist_ids: artist1.id).published.count).to eq 1
204
- expect(Artwork.in(artist_ids: artist2.id).published.count).to eq 0
205
- end
206
- end
207
- end
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Slug::Criteria do
4
+ describe '.find' do
5
+ let!(:book) { Book.create(title: 'A Working Title').tap { |d| d.update_attribute(:title, 'A Thousand Plateaus') } }
6
+ let!(:book2) { Book.create(title: 'Difference and Repetition') }
7
+ let!(:friend) { Friend.create(name: 'Jim Bob') }
8
+ let!(:friend2) { Friend.create(name: friend.id.to_s) }
9
+ let!(:integer_id) { IntegerId.new(name: 'I have integer ids').tap { |d| d.id = 123; d.save! } }
10
+ let!(:integer_id2) { IntegerId.new(name: integer_id.id.to_s).tap { |d| d.id = 456; d.save! } }
11
+ let!(:string_id) { StringId.new(name: 'I have string ids').tap { |d| d.id = 'abc'; d.save! } }
12
+ let!(:string_id2) { StringId.new(name: string_id.id.to_s).tap { |d| d.id = 'def'; d.save! } }
13
+ let!(:subject) { Subject.create(name: 'A Subject', book: book) }
14
+ let!(:subject2) { Subject.create(name: 'A Subject', book: book2) }
15
+ let!(:without_slug) { WithoutSlug.new.tap { |d| d.id = 456; d.save! } }
16
+
17
+ context 'when the model does not use mongoid slugs' do
18
+ it "should not use mongoid slug's custom find methods" do
19
+ expect_any_instance_of(Mongoid::Slug::Criteria).not_to receive(:find)
20
+ expect(WithoutSlug.find(without_slug.id.to_s)).to eq(without_slug)
21
+ end
22
+ end
23
+
24
+ context 'using slugs' do
25
+ context '(single)' do
26
+ context 'and a document is found' do
27
+ it 'returns the document as an object' do
28
+ expect(Book.find(book.slugs.first)).to eq(book)
29
+ end
30
+ end
31
+
32
+ context 'but no document is found' do
33
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
34
+ expect do
35
+ Book.find('Anti Oedipus')
36
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
37
+ end
38
+ end
39
+ end
40
+
41
+ context '(multiple)' do
42
+ context 'and all documents are found' do
43
+ it 'returns the documents as an array without duplication' do
44
+ expect(Book.find(book.slugs + book2.slugs)).to match_array([book, book2])
45
+ end
46
+ end
47
+
48
+ context 'but not all documents are found' do
49
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
50
+ expect do
51
+ Book.find(book.slugs + ['something-nonexistent'])
52
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when no documents match' do
58
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
59
+ expect do
60
+ Book.find('Anti Oedipus')
61
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
62
+ end
63
+ end
64
+
65
+ context 'when ids are BSON::ObjectIds and the supplied argument looks like a BSON::ObjectId' do
66
+ it 'it should find based on ids not slugs' do # i.e. it should type cast the argument
67
+ expect(Friend.find(friend.id.to_s)).to eq(friend)
68
+ end
69
+ end
70
+
71
+ context 'when ids are Strings' do
72
+ it 'it should find based on ids not slugs' do # i.e. string ids should take precedence over string slugs
73
+ expect(StringId.find(string_id.id.to_s)).to eq(string_id)
74
+ end
75
+ end
76
+
77
+ context 'when ids are Integers and the supplied arguments looks like an Integer' do
78
+ it 'it should find based on slugs not ids' do # i.e. it should not type cast the argument
79
+ expect(IntegerId.find(integer_id.id.to_s)).to eq(integer_id2)
80
+ end
81
+ end
82
+
83
+ context 'models that does not use slugs, should find using the original find' do
84
+ it 'it should find based on ids' do # i.e. it should not type cast the argument
85
+ expect(WithoutSlug.find(without_slug.id.to_s)).to eq(without_slug)
86
+ end
87
+ end
88
+
89
+ context 'when scoped' do
90
+ context 'and a document is found' do
91
+ it 'returns the document as an object' do
92
+ expect(book.subjects.find(subject.slugs.first)).to eq(subject)
93
+ expect(book2.subjects.find(subject.slugs.first)).to eq(subject2)
94
+ end
95
+ end
96
+
97
+ context 'but no document is found' do
98
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
99
+ expect do
100
+ book.subjects.find('Another Subject')
101
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ context 'using ids' do
108
+ it 'raises a Mongoid::Errors::DocumentNotFound error if no document is found' do
109
+ expect do
110
+ Book.find(friend.id)
111
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
112
+ end
113
+
114
+ context 'given a single document' do
115
+ it 'returns the document' do
116
+ expect(Friend.find(friend.id)).to eq(friend)
117
+ end
118
+ end
119
+
120
+ context 'given multiple documents' do
121
+ it 'returns the documents' do
122
+ expect(Book.find([book.id, book2.id])).to match_array([book, book2])
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '.find_by_slug!' do
129
+ let!(:book) { Book.create(title: 'A Working Title').tap { |d| d.update_attribute(:title, 'A Thousand Plateaus') } }
130
+ let!(:book2) { Book.create(title: 'Difference and Repetition') }
131
+ let!(:friend) { Friend.create(name: 'Jim Bob') }
132
+ let!(:friend2) { Friend.create(name: friend.id.to_s) }
133
+ let!(:integer_id) { IntegerId.new(name: 'I have integer ids').tap { |d| d.id = 123; d.save! } }
134
+ let!(:integer_id2) { IntegerId.new(name: integer_id.id.to_s).tap { |d| d.id = 456; d.save! } }
135
+ let!(:string_id) { StringId.new(name: 'I have string ids').tap { |d| d.id = 'abc'; d.save! } }
136
+ let!(:string_id2) { StringId.new(name: string_id.id.to_s).tap { |d| d.id = 'def'; d.save! } }
137
+ let!(:subject) { Subject.create(name: 'A Subject', book: book) }
138
+ let!(:subject2) { Subject.create(name: 'A Subject', book: book2) }
139
+
140
+ context '(single)' do
141
+ context 'and a document is found' do
142
+ it 'returns the document as an object' do
143
+ expect(Book.find_by_slug!(book.slugs.first)).to eq(book)
144
+ end
145
+ end
146
+
147
+ context 'but no document is found' do
148
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
149
+ expect do
150
+ Book.find_by_slug!('Anti Oedipus')
151
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
152
+ end
153
+ end
154
+ end
155
+
156
+ context '(multiple)' do
157
+ context 'and all documents are found' do
158
+ it 'returns the documents as an array without duplication' do
159
+ expect(Book.find_by_slug!(book.slugs + book2.slugs)).to match_array([book, book2])
160
+ end
161
+ end
162
+
163
+ context 'but not all documents are found' do
164
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
165
+ expect do
166
+ Book.find_by_slug!(book.slugs + ['something-nonexistent'])
167
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
168
+ end
169
+ end
170
+ end
171
+
172
+ context 'when scoped' do
173
+ context 'and a document is found' do
174
+ it 'returns the document as an object' do
175
+ expect(book.subjects.find_by_slug!(subject.slugs.first)).to eq(subject)
176
+ expect(book2.subjects.find_by_slug!(subject.slugs.first)).to eq(subject2)
177
+ end
178
+ end
179
+
180
+ context 'but no document is found' do
181
+ it 'raises a Mongoid::Errors::DocumentNotFound error' do
182
+ expect do
183
+ book.subjects.find_by_slug!('Another Subject')
184
+ end.to raise_error(Mongoid::Errors::DocumentNotFound)
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ describe '.where' do
191
+ let!(:artist1) { Artist.create!(name: 'Leonardo') }
192
+ let!(:artist2) { Artist.create!(name: 'Malevich') }
193
+ let!(:artwork1) { Artwork.create!(title: 'Mona Lisa', artist_ids: [artist1.id], published: true) }
194
+ let!(:artwork2) { Artwork.create!(title: 'Black Square', artist_ids: [artist2.id], published: false) }
195
+ let!(:artwork3) { Artwork.create! }
196
+
197
+ it 'counts artworks' do
198
+ expect(Artwork.in(artist_ids: artist1.id).count).to eq 1
199
+ expect(Artwork.in(artist_ids: artist2.id).count).to eq 1
200
+ end
201
+
202
+ it 'counts published artworks' do
203
+ expect(Artwork.in(artist_ids: artist1.id).published.count).to eq 1
204
+ expect(Artwork.in(artist_ids: artist2.id).published.count).to eq 0
205
+ end
206
+ end
207
+ end