friendly_id 5.5.1 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changelog.md +4 -1
- data/README.md +3 -3
- data/lib/friendly_id/history.rb +2 -2
- data/lib/friendly_id/slug_generator.rb +15 -0
- data/lib/friendly_id/slugged.rb +19 -1
- data/lib/friendly_id/version.rb +1 -1
- metadata +5 -76
- checksums.yaml.gz.sig +0 -0
- data/.gemtest +0 -0
- data/.github/FUNDING.yml +0 -1
- data/.github/dependabot.yml +0 -6
- data/.github/stale.yml +0 -17
- data/.github/workflows/test.yml +0 -62
- data/.gitignore +0 -14
- data/.yardopts +0 -8
- data/CONTRIBUTING.md +0 -11
- data/Gemfile +0 -23
- data/Rakefile +0 -104
- data/UPGRADING.md +0 -115
- data/bench.rb +0 -84
- data/certs/parndt.pem +0 -27
- data/friendly_id.gemspec +0 -36
- data/gemfiles/Gemfile.rails-5.2.rb +0 -22
- data/gemfiles/Gemfile.rails-6.0.rb +0 -22
- data/gemfiles/Gemfile.rails-6.1.rb +0 -22
- data/gemfiles/Gemfile.rails-7.0.rb +0 -22
- data/guide.rb +0 -24
- data/test/base_test.rb +0 -69
- data/test/benchmarks/finders.rb +0 -90
- data/test/benchmarks/object_utils.rb +0 -56
- data/test/candidates_test.rb +0 -142
- data/test/configuration_test.rb +0 -60
- data/test/core_test.rb +0 -35
- data/test/databases.yml +0 -22
- data/test/finders_test.rb +0 -76
- data/test/generator_test.rb +0 -38
- data/test/helper.rb +0 -125
- data/test/history_test.rb +0 -434
- data/test/numeric_slug_test.rb +0 -31
- data/test/object_utils_test.rb +0 -27
- data/test/reserved_test.rb +0 -73
- data/test/schema.rb +0 -117
- data/test/scoped_test.rb +0 -95
- data/test/sequentially_slugged_test.rb +0 -214
- data/test/shared.rb +0 -181
- data/test/simple_i18n_test.rb +0 -144
- data/test/slugged_test.rb +0 -628
- data/test/sti_test.rb +0 -135
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
data/test/history_test.rb
DELETED
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
require "helper"
|
|
2
|
-
|
|
3
|
-
class HistoryTest < TestCaseClass
|
|
4
|
-
include FriendlyId::Test
|
|
5
|
-
include FriendlyId::Test::Shared::Core
|
|
6
|
-
|
|
7
|
-
class Manual < ActiveRecord::Base
|
|
8
|
-
extend FriendlyId
|
|
9
|
-
friendly_id :name, use: [:slugged, :history]
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def model_class
|
|
13
|
-
Manual
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
test "should insert record in slugs table on create" do
|
|
17
|
-
with_instance_of(model_class) { |record| assert record.slugs.any? }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
test "should not create new slug record if friendly_id is not changed" do
|
|
21
|
-
with_instance_of(model_class) do |record|
|
|
22
|
-
record.active = true
|
|
23
|
-
record.save!
|
|
24
|
-
assert_equal 1, FriendlyId::Slug.count
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
test "should create new slug record when friendly_id changes" do
|
|
29
|
-
with_instance_of(model_class) do |record|
|
|
30
|
-
record.name = record.name + "b"
|
|
31
|
-
record.slug = nil
|
|
32
|
-
record.save!
|
|
33
|
-
assert_equal 2, FriendlyId::Slug.count
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
test "should be findable by old slugs" do
|
|
38
|
-
with_instance_of(model_class) do |record|
|
|
39
|
-
old_friendly_id = record.friendly_id
|
|
40
|
-
record.name = record.name + "b"
|
|
41
|
-
record.slug = nil
|
|
42
|
-
record.save!
|
|
43
|
-
begin
|
|
44
|
-
assert model_class.friendly.find(old_friendly_id)
|
|
45
|
-
assert model_class.friendly.exists?(old_friendly_id), "should exist? by old id"
|
|
46
|
-
rescue ActiveRecord::RecordNotFound
|
|
47
|
-
flunk "Could not find record by old id"
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
test "should create slug records on each change" do
|
|
53
|
-
transaction do
|
|
54
|
-
model_class.create! name: "hello"
|
|
55
|
-
assert_equal 1, FriendlyId::Slug.count
|
|
56
|
-
|
|
57
|
-
record = model_class.friendly.find("hello")
|
|
58
|
-
record.name = "hello again"
|
|
59
|
-
record.slug = nil
|
|
60
|
-
record.save!
|
|
61
|
-
assert_equal 2, FriendlyId::Slug.count
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
test "should not be read only when found by slug" do
|
|
66
|
-
with_instance_of(model_class) do |record|
|
|
67
|
-
refute model_class.friendly.find(record.friendly_id).readonly?
|
|
68
|
-
assert record.update name: "foo"
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
test "should not be read only when found by old slug" do
|
|
73
|
-
with_instance_of(model_class) do |record|
|
|
74
|
-
old_friendly_id = record.friendly_id
|
|
75
|
-
record.name = record.name + "b"
|
|
76
|
-
record.save!
|
|
77
|
-
assert !model_class.friendly.find(old_friendly_id).readonly?
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
test "should handle renames" do
|
|
82
|
-
with_instance_of(model_class) do |record|
|
|
83
|
-
record.name = "x"
|
|
84
|
-
record.slug = nil
|
|
85
|
-
assert record.save
|
|
86
|
-
record.name = "y"
|
|
87
|
-
record.slug = nil
|
|
88
|
-
assert record.save
|
|
89
|
-
record.name = "x"
|
|
90
|
-
record.slug = nil
|
|
91
|
-
assert record.save
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
test "should maintain history even if current slug is not the most recent one" do
|
|
96
|
-
with_instance_of(model_class) do |record|
|
|
97
|
-
record.name = "current"
|
|
98
|
-
assert record.save
|
|
99
|
-
|
|
100
|
-
# this feels like a hack. only thing i can get to work with the HistoryTestWithSti
|
|
101
|
-
# test cases. (Editorialist vs Journalist.)
|
|
102
|
-
sluggable_type = FriendlyId::Slug.first.sluggable_type
|
|
103
|
-
# create several slugs for record
|
|
104
|
-
# current slug does not have max id
|
|
105
|
-
FriendlyId::Slug.delete_all
|
|
106
|
-
FriendlyId::Slug.create(sluggable_type: sluggable_type, sluggable_id: record.id, slug: "current")
|
|
107
|
-
FriendlyId::Slug.create(sluggable_type: sluggable_type, sluggable_id: record.id, slug: "outdated")
|
|
108
|
-
|
|
109
|
-
record.reload
|
|
110
|
-
record.slug = nil
|
|
111
|
-
assert record.save
|
|
112
|
-
|
|
113
|
-
assert_equal 2, FriendlyId::Slug.count
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
test "should not create new slugs that match old slugs" do
|
|
118
|
-
transaction do
|
|
119
|
-
first_record = model_class.create! name: "foo"
|
|
120
|
-
first_record.name = "bar"
|
|
121
|
-
first_record.save!
|
|
122
|
-
second_record = model_class.create! name: "foo"
|
|
123
|
-
assert second_record.slug != "foo"
|
|
124
|
-
assert_match(/foo-.+/, second_record.slug)
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
test "should not fail when updating historic slugs" do
|
|
129
|
-
transaction do
|
|
130
|
-
first_record = model_class.create! name: "foo"
|
|
131
|
-
second_record = model_class.create! name: "another"
|
|
132
|
-
|
|
133
|
-
second_record.update name: "foo", slug: nil
|
|
134
|
-
assert_match(/foo-.*/, second_record.slug)
|
|
135
|
-
|
|
136
|
-
first_record.update name: "another", slug: nil
|
|
137
|
-
assert_match(/another-.*/, first_record.slug)
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
test "should prefer product that used slug most recently" do
|
|
142
|
-
transaction do
|
|
143
|
-
first_record = model_class.create! name: "foo"
|
|
144
|
-
second_record = model_class.create! name: "bar"
|
|
145
|
-
|
|
146
|
-
first_record.update! slug: "not_foo"
|
|
147
|
-
second_record.update! slug: "foo" # now both records have used foo; second_record most recently
|
|
148
|
-
second_record.update! slug: "not_bar"
|
|
149
|
-
|
|
150
|
-
assert_equal model_class.friendly.find("foo"), second_record
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
test "should name table according to prefix and suffix" do
|
|
155
|
-
transaction do
|
|
156
|
-
prefix = "prefix_"
|
|
157
|
-
without_prefix = FriendlyId::Slug.table_name
|
|
158
|
-
ActiveRecord::Base.table_name_prefix = prefix
|
|
159
|
-
FriendlyId::Slug.reset_table_name
|
|
160
|
-
assert_equal prefix + without_prefix, FriendlyId::Slug.table_name
|
|
161
|
-
ensure
|
|
162
|
-
ActiveRecord::Base.table_name_prefix = ""
|
|
163
|
-
FriendlyId::Slug.table_name = without_prefix
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
class HistoryTestWithAutomaticSlugRegeneration < HistoryTest
|
|
169
|
-
class Manual < ActiveRecord::Base
|
|
170
|
-
extend FriendlyId
|
|
171
|
-
friendly_id :name, use: [:slugged, :history]
|
|
172
|
-
|
|
173
|
-
def should_generate_new_friendly_id?
|
|
174
|
-
slug.blank? or name_changed?
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def model_class
|
|
179
|
-
Manual
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
test "should allow reversion back to a previously used slug" do
|
|
183
|
-
with_instance_of(model_class, name: "foo") do |record|
|
|
184
|
-
record.name = "bar"
|
|
185
|
-
record.save!
|
|
186
|
-
assert_equal "bar", record.friendly_id
|
|
187
|
-
record.name = "foo"
|
|
188
|
-
record.save!
|
|
189
|
-
assert_equal "foo", record.friendly_id
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
class DependentDestroyTest < TestCaseClass
|
|
195
|
-
include FriendlyId::Test
|
|
196
|
-
|
|
197
|
-
class FalseManual < ActiveRecord::Base
|
|
198
|
-
self.table_name = "manuals"
|
|
199
|
-
|
|
200
|
-
extend FriendlyId
|
|
201
|
-
friendly_id :name, use: :history, dependent: false
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
class DefaultManual < ActiveRecord::Base
|
|
205
|
-
self.table_name = "manuals"
|
|
206
|
-
|
|
207
|
-
extend FriendlyId
|
|
208
|
-
friendly_id :name, use: :history
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
test "should allow disabling of dependent destroy" do
|
|
212
|
-
transaction do
|
|
213
|
-
assert FriendlyId::Slug.find_by_slug("foo").nil?
|
|
214
|
-
l = FalseManual.create! name: "foo"
|
|
215
|
-
assert FriendlyId::Slug.find_by_slug("foo").present?
|
|
216
|
-
l.destroy
|
|
217
|
-
assert FriendlyId::Slug.find_by_slug("foo").present?
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
test "should dependently destroy by default" do
|
|
222
|
-
transaction do
|
|
223
|
-
assert FriendlyId::Slug.find_by_slug("baz").nil?
|
|
224
|
-
l = DefaultManual.create! name: "baz"
|
|
225
|
-
assert FriendlyId::Slug.find_by_slug("baz").present?
|
|
226
|
-
l.destroy
|
|
227
|
-
assert FriendlyId::Slug.find_by_slug("baz").nil?
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
if ActiveRecord::VERSION::STRING >= "5.0"
|
|
233
|
-
class HistoryTestWithParanoidDeletes < HistoryTest
|
|
234
|
-
class ParanoidRecord < ActiveRecord::Base
|
|
235
|
-
extend FriendlyId
|
|
236
|
-
friendly_id :name, use: :history, dependent: false
|
|
237
|
-
|
|
238
|
-
default_scope { where(deleted_at: nil) }
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def model_class
|
|
242
|
-
ParanoidRecord
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
test "slug should have a sluggable even when soft deleted by a library" do
|
|
246
|
-
transaction do
|
|
247
|
-
assert FriendlyId::Slug.find_by_slug("paranoid").nil?
|
|
248
|
-
record = model_class.create(name: "paranoid")
|
|
249
|
-
assert FriendlyId::Slug.find_by_slug("paranoid").present?
|
|
250
|
-
|
|
251
|
-
record.update deleted_at: Time.now
|
|
252
|
-
|
|
253
|
-
orphan_slug = FriendlyId::Slug.find_by_slug("paranoid")
|
|
254
|
-
assert orphan_slug.present?, "Orphaned slug should exist"
|
|
255
|
-
|
|
256
|
-
assert orphan_slug.valid?, "Errors: #{orphan_slug.errors.full_messages}"
|
|
257
|
-
assert orphan_slug.sluggable.present?, "Orphaned slug should still find corresponding paranoid sluggable"
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
class HistoryTestWithSti < HistoryTest
|
|
264
|
-
class Journalist < ActiveRecord::Base
|
|
265
|
-
extend FriendlyId
|
|
266
|
-
friendly_id :name, use: [:slugged, :history]
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
class Editorialist < Journalist
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
def model_class
|
|
273
|
-
Editorialist
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
class HistoryTestWithFriendlyFinders < HistoryTest
|
|
278
|
-
class Journalist < ActiveRecord::Base
|
|
279
|
-
extend FriendlyId
|
|
280
|
-
friendly_id :name, use: [:slugged, :finders, :history]
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
class Restaurant < ActiveRecord::Base
|
|
284
|
-
extend FriendlyId
|
|
285
|
-
belongs_to :city
|
|
286
|
-
friendly_id :name, use: [:slugged, :history, :finders]
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
test "should be findable by old slugs" do
|
|
290
|
-
[Journalist, Restaurant].each do |model_class|
|
|
291
|
-
with_instance_of(model_class) do |record|
|
|
292
|
-
old_friendly_id = record.friendly_id
|
|
293
|
-
record.name = record.name + "b"
|
|
294
|
-
record.slug = nil
|
|
295
|
-
record.save!
|
|
296
|
-
begin
|
|
297
|
-
assert model_class.find(old_friendly_id)
|
|
298
|
-
assert model_class.exists?(old_friendly_id), "should exist? by old id for #{model_class.name}"
|
|
299
|
-
rescue ActiveRecord::RecordNotFound
|
|
300
|
-
flunk "Could not find record by old id for #{model_class.name}"
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
end
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
class HistoryTestWithFindersBeforeHistory < HistoryTest
|
|
308
|
-
class Novelist < ActiveRecord::Base
|
|
309
|
-
has_many :novels
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
class Novel < ActiveRecord::Base
|
|
313
|
-
extend FriendlyId
|
|
314
|
-
|
|
315
|
-
belongs_to :novelist
|
|
316
|
-
|
|
317
|
-
friendly_id :name, use: [:finders, :history]
|
|
318
|
-
|
|
319
|
-
def should_generate_new_friendly_id?
|
|
320
|
-
slug.blank? || name_changed?
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
test "should be findable by old slug through has_many association" do
|
|
325
|
-
transaction do
|
|
326
|
-
novelist = Novelist.create!(name: "Stephen King")
|
|
327
|
-
novel = novelist.novels.create(name: "Rita Hayworth and Shawshank Redemption")
|
|
328
|
-
slug = novel.slug
|
|
329
|
-
novel.name = "Shawshank Redemption"
|
|
330
|
-
novel.save!
|
|
331
|
-
assert_equal novel, Novel.find(slug)
|
|
332
|
-
assert_equal novel, novelist.novels.find(slug)
|
|
333
|
-
end
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
class City < ActiveRecord::Base
|
|
338
|
-
has_many :restaurants
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
class Restaurant < ActiveRecord::Base
|
|
342
|
-
extend FriendlyId
|
|
343
|
-
belongs_to :city
|
|
344
|
-
friendly_id :name, use: [:scoped, :history], scope: :city
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
class ScopedHistoryTest < TestCaseClass
|
|
348
|
-
include FriendlyId::Test
|
|
349
|
-
include FriendlyId::Test::Shared::Core
|
|
350
|
-
|
|
351
|
-
def model_class
|
|
352
|
-
Restaurant
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
test "should find old scoped slugs" do
|
|
356
|
-
transaction do
|
|
357
|
-
city = City.create!
|
|
358
|
-
with_instance_of(Restaurant) do |record|
|
|
359
|
-
record.city = city
|
|
360
|
-
|
|
361
|
-
record.name = "x"
|
|
362
|
-
record.slug = nil
|
|
363
|
-
record.save!
|
|
364
|
-
|
|
365
|
-
record.name = "y"
|
|
366
|
-
record.slug = nil
|
|
367
|
-
record.save!
|
|
368
|
-
|
|
369
|
-
assert_equal city.restaurants.friendly.find("x"), city.restaurants.friendly.find("y")
|
|
370
|
-
end
|
|
371
|
-
end
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
test "should consider old scoped slugs when creating slugs" do
|
|
375
|
-
transaction do
|
|
376
|
-
city = City.create!
|
|
377
|
-
with_instance_of(Restaurant) do |record|
|
|
378
|
-
record.city = city
|
|
379
|
-
|
|
380
|
-
record.name = "x"
|
|
381
|
-
record.slug = nil
|
|
382
|
-
record.save!
|
|
383
|
-
|
|
384
|
-
record.name = "y"
|
|
385
|
-
record.slug = nil
|
|
386
|
-
record.save!
|
|
387
|
-
|
|
388
|
-
second_record = model_class.create! city: city, name: "x"
|
|
389
|
-
assert_match(/x-.+/, second_record.friendly_id)
|
|
390
|
-
|
|
391
|
-
third_record = model_class.create! city: city, name: "y"
|
|
392
|
-
assert_match(/y-.+/, third_record.friendly_id)
|
|
393
|
-
end
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
test "should record history when scope changes" do
|
|
398
|
-
transaction do
|
|
399
|
-
city1 = City.create!
|
|
400
|
-
city2 = City.create!
|
|
401
|
-
with_instance_of(Restaurant) do |record|
|
|
402
|
-
record.name = "x"
|
|
403
|
-
record.slug = nil
|
|
404
|
-
|
|
405
|
-
record.city = city1
|
|
406
|
-
record.save!
|
|
407
|
-
assert_equal("city_id:#{city1.id}", record.slugs.reload.first.scope)
|
|
408
|
-
assert_equal("x", record.slugs.reload.first.slug)
|
|
409
|
-
|
|
410
|
-
record.city = city2
|
|
411
|
-
record.save!
|
|
412
|
-
assert_equal("city_id:#{city2.id}", record.slugs.reload.first.scope)
|
|
413
|
-
|
|
414
|
-
record.name = "y"
|
|
415
|
-
record.slug = nil
|
|
416
|
-
record.city = city1
|
|
417
|
-
record.save!
|
|
418
|
-
assert_equal("city_id:#{city1.id}", record.slugs.reload.first.scope)
|
|
419
|
-
assert_equal("y", record.slugs.reload.first.slug)
|
|
420
|
-
end
|
|
421
|
-
end
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
test "should allow equal slugs in different scopes" do
|
|
425
|
-
transaction do
|
|
426
|
-
city = City.create!
|
|
427
|
-
second_city = City.create!
|
|
428
|
-
record = model_class.create! city: city, name: "x"
|
|
429
|
-
second_record = model_class.create! city: second_city, name: "x"
|
|
430
|
-
|
|
431
|
-
assert_equal record.slug, second_record.slug
|
|
432
|
-
end
|
|
433
|
-
end
|
|
434
|
-
end
|
data/test/numeric_slug_test.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
require "helper"
|
|
2
|
-
|
|
3
|
-
class NumericSlugTest < TestCaseClass
|
|
4
|
-
include FriendlyId::Test
|
|
5
|
-
include FriendlyId::Test::Shared::Core
|
|
6
|
-
|
|
7
|
-
def model_class
|
|
8
|
-
Article
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
test "should generate numeric slugs" do
|
|
12
|
-
transaction do
|
|
13
|
-
record = model_class.create! name: "123"
|
|
14
|
-
assert_equal "123", record.slug
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
test "should find by numeric slug" do
|
|
19
|
-
transaction do
|
|
20
|
-
record = model_class.create! name: "123"
|
|
21
|
-
assert_equal model_class.friendly.find("123").id, record.id
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
test "should exist? by numeric slug" do
|
|
26
|
-
transaction do
|
|
27
|
-
model_class.create! name: "123"
|
|
28
|
-
assert model_class.friendly.exists?("123")
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
data/test/object_utils_test.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
require "helper"
|
|
2
|
-
|
|
3
|
-
class ObjectUtilsTest < TestCaseClass
|
|
4
|
-
include FriendlyId::Test
|
|
5
|
-
|
|
6
|
-
test "strings with letters are friendly_ids" do
|
|
7
|
-
assert "a".friendly_id?
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
test "integers should be unfriendly ids" do
|
|
11
|
-
assert 1.unfriendly_id?
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
test "numeric strings are neither friendly nor unfriendly" do
|
|
15
|
-
assert_nil "1".friendly_id?
|
|
16
|
-
assert_nil "1".unfriendly_id?
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
test "ActiveRecord::Base instances should be unfriendly_ids" do
|
|
20
|
-
FriendlyId.mark_as_unfriendly(ActiveRecord::Base)
|
|
21
|
-
|
|
22
|
-
model_class = Class.new(ActiveRecord::Base) do
|
|
23
|
-
self.table_name = "authors"
|
|
24
|
-
end
|
|
25
|
-
assert model_class.new.unfriendly_id?
|
|
26
|
-
end
|
|
27
|
-
end
|
data/test/reserved_test.rb
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
require "helper"
|
|
2
|
-
|
|
3
|
-
class ReservedTest < TestCaseClass
|
|
4
|
-
include FriendlyId::Test
|
|
5
|
-
|
|
6
|
-
class Journalist < ActiveRecord::Base
|
|
7
|
-
extend FriendlyId
|
|
8
|
-
friendly_id :slug_candidates, use: [:slugged, :reserved], reserved_words: %w[new edit]
|
|
9
|
-
|
|
10
|
-
after_validation :move_friendly_id_error_to_name
|
|
11
|
-
|
|
12
|
-
def move_friendly_id_error_to_name
|
|
13
|
-
errors.add :name, *errors.delete(:friendly_id) if errors[:friendly_id].present?
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def slug_candidates
|
|
17
|
-
name
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def model_class
|
|
22
|
-
Journalist
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
test "should reserve words" do
|
|
26
|
-
%w[new edit NEW Edit].each do |word|
|
|
27
|
-
transaction do
|
|
28
|
-
assert_raises(ActiveRecord::RecordInvalid) { model_class.create! name: word }
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
test "should move friendly_id error to name" do
|
|
34
|
-
with_instance_of(model_class) do |record|
|
|
35
|
-
record.errors.add :name, "xxx"
|
|
36
|
-
record.errors.add :friendly_id, "yyy"
|
|
37
|
-
record.move_friendly_id_error_to_name
|
|
38
|
-
assert record.errors[:name].present? && record.errors[:friendly_id].blank?
|
|
39
|
-
assert_equal 2, record.errors.count
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
test "should reject reserved candidates" do
|
|
44
|
-
transaction do
|
|
45
|
-
record = model_class.new(name: "new")
|
|
46
|
-
def record.slug_candidates
|
|
47
|
-
[:name, "foo"]
|
|
48
|
-
end
|
|
49
|
-
record.save!
|
|
50
|
-
assert_equal "foo", record.friendly_id
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
test "should be invalid if all candidates are reserved" do
|
|
55
|
-
transaction do
|
|
56
|
-
record = model_class.new(name: "new")
|
|
57
|
-
def record.slug_candidates
|
|
58
|
-
["edit", "new"]
|
|
59
|
-
end
|
|
60
|
-
assert_raises(ActiveRecord::RecordInvalid) { record.save! }
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
test "should optionally treat reserved words as conflict" do
|
|
65
|
-
klass = Class.new(model_class) do
|
|
66
|
-
friendly_id :slug_candidates, use: [:slugged, :reserved], reserved_words: %w[new edit], treat_reserved_as_conflict: true
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
with_instance_of(klass, name: "new") do |record|
|
|
70
|
-
assert_match(/new-([0-9a-z]+-){4}[0-9a-z]+\z/, record.slug)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
data/test/schema.rb
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
require "friendly_id/migration"
|
|
2
|
-
|
|
3
|
-
module FriendlyId
|
|
4
|
-
module Test
|
|
5
|
-
migration_class =
|
|
6
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
|
7
|
-
ActiveRecord::Migration[4.2]
|
|
8
|
-
else
|
|
9
|
-
ActiveRecord::Migration
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
class Schema < migration_class
|
|
13
|
-
class << self
|
|
14
|
-
def down
|
|
15
|
-
CreateFriendlyIdSlugs.down
|
|
16
|
-
tables.each do |name|
|
|
17
|
-
drop_table name
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def up
|
|
22
|
-
# TODO: use schema version to avoid ugly hacks like this
|
|
23
|
-
return if @done
|
|
24
|
-
CreateFriendlyIdSlugs.migrate :up
|
|
25
|
-
|
|
26
|
-
tables.each do |table_name|
|
|
27
|
-
create_table table_name do |t|
|
|
28
|
-
t.string :name
|
|
29
|
-
t.boolean :active
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
tables_with_uuid_primary_key.each do |table_name|
|
|
34
|
-
create_table table_name, primary_key: :uuid_key, id: false do |t|
|
|
35
|
-
t.string :name
|
|
36
|
-
t.string :uuid_key, null: false
|
|
37
|
-
t.string :slug
|
|
38
|
-
end
|
|
39
|
-
add_index table_name, :slug, unique: true
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
slugged_tables.each do |table_name|
|
|
43
|
-
add_column table_name, :slug, :string
|
|
44
|
-
add_index table_name, :slug, unique: true if table_name != "novels"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
scoped_tables.each do |table_name|
|
|
48
|
-
add_column table_name, :slug, :string
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
paranoid_tables.each do |table_name|
|
|
52
|
-
add_column table_name, :slug, :string
|
|
53
|
-
add_column table_name, :deleted_at, :datetime
|
|
54
|
-
add_index table_name, :deleted_at
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# This will be used to test scopes
|
|
58
|
-
add_column :novels, :novelist_id, :integer
|
|
59
|
-
add_column :novels, :publisher_id, :integer
|
|
60
|
-
add_index :novels, [:slug, :publisher_id, :novelist_id], unique: true
|
|
61
|
-
|
|
62
|
-
# This will be used to test column name quoting
|
|
63
|
-
add_column :journalists, "strange name", :string
|
|
64
|
-
|
|
65
|
-
# This will be used to test STI
|
|
66
|
-
add_column :journalists, "type", :string
|
|
67
|
-
|
|
68
|
-
# These will be used to test i18n
|
|
69
|
-
add_column :journalists, "slug_en", :string
|
|
70
|
-
add_column :journalists, "slug_es", :string
|
|
71
|
-
add_column :journalists, "slug_de", :string
|
|
72
|
-
add_column :journalists, "slug_fr_ca", :string
|
|
73
|
-
|
|
74
|
-
# This will be used to test relationships
|
|
75
|
-
add_column :books, :author_id, :integer
|
|
76
|
-
|
|
77
|
-
# Used to test :scoped and :history together
|
|
78
|
-
add_column :restaurants, :city_id, :integer
|
|
79
|
-
|
|
80
|
-
# Used to test candidates
|
|
81
|
-
add_column :cities, :code, :string, limit: 3
|
|
82
|
-
|
|
83
|
-
# Used as a non-default slug_column
|
|
84
|
-
add_column :authors, :subdomain, :string
|
|
85
|
-
|
|
86
|
-
@done = true
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
private
|
|
90
|
-
|
|
91
|
-
def slugged_tables
|
|
92
|
-
%w[journalists articles novelists novels manuals cities]
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def paranoid_tables
|
|
96
|
-
["paranoid_records"]
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def tables_with_uuid_primary_key
|
|
100
|
-
["menu_items"]
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def scoped_tables
|
|
104
|
-
["restaurants"]
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def simple_tables
|
|
108
|
-
%w[authors books publishers]
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def tables
|
|
112
|
-
simple_tables + slugged_tables + scoped_tables + paranoid_tables
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|