friendly_id 5.4.2 → 5.5.1
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
- checksums.yaml.gz.sig +0 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/test.yml +38 -25
- data/.yardopts +2 -0
- data/Changelog.md +10 -0
- data/Gemfile +9 -13
- data/README.md +21 -0
- data/Rakefile +24 -27
- data/bench.rb +30 -27
- data/certs/parndt.pem +25 -23
- data/friendly_id.gemspec +26 -29
- data/gemfiles/Gemfile.rails-5.2.rb +11 -16
- data/gemfiles/Gemfile.rails-6.0.rb +11 -16
- data/gemfiles/Gemfile.rails-6.1.rb +22 -0
- data/gemfiles/Gemfile.rails-7.0.rb +22 -0
- data/guide.rb +13 -6
- data/lib/friendly_id/base.rb +59 -60
- data/lib/friendly_id/candidates.rb +9 -11
- data/lib/friendly_id/configuration.rb +6 -7
- data/lib/friendly_id/finder_methods.rb +26 -11
- data/lib/friendly_id/finders.rb +66 -66
- data/lib/friendly_id/history.rb +62 -63
- data/lib/friendly_id/initializer.rb +4 -4
- data/lib/friendly_id/migration.rb +6 -6
- data/lib/friendly_id/object_utils.rb +2 -2
- data/lib/friendly_id/reserved.rb +30 -32
- data/lib/friendly_id/scoped.rb +99 -102
- data/lib/friendly_id/sequentially_slugged/calculator.rb +69 -0
- data/lib/friendly_id/sequentially_slugged.rb +17 -64
- data/lib/friendly_id/simple_i18n.rb +78 -69
- data/lib/friendly_id/slug.rb +1 -2
- data/lib/friendly_id/slug_generator.rb +1 -3
- data/lib/friendly_id/slugged.rb +236 -238
- data/lib/friendly_id/version.rb +1 -1
- data/lib/friendly_id.rb +47 -49
- data/lib/generators/friendly_id_generator.rb +9 -9
- data/test/base_test.rb +10 -13
- data/test/benchmarks/finders.rb +28 -26
- data/test/benchmarks/object_utils.rb +13 -13
- data/test/candidates_test.rb +17 -18
- data/test/configuration_test.rb +7 -11
- data/test/core_test.rb +1 -2
- data/test/databases.yml +4 -3
- data/test/finders_test.rb +52 -5
- data/test/generator_test.rb +16 -26
- data/test/helper.rb +31 -24
- data/test/history_test.rb +70 -74
- data/test/numeric_slug_test.rb +4 -4
- data/test/object_utils_test.rb +0 -2
- data/test/reserved_test.rb +9 -11
- data/test/schema.rb +5 -4
- data/test/scoped_test.rb +18 -20
- data/test/sequentially_slugged_test.rb +65 -50
- data/test/shared.rb +15 -16
- data/test/simple_i18n_test.rb +22 -12
- data/test/slugged_test.rb +102 -121
- data/test/sti_test.rb +19 -21
- data.tar.gz.sig +0 -0
- metadata +37 -32
- metadata.gz.sig +0 -0
data/test/history_test.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
require "helper"
|
2
2
|
|
3
3
|
class HistoryTest < TestCaseClass
|
4
|
-
|
5
4
|
include FriendlyId::Test
|
6
5
|
include FriendlyId::Test::Shared::Core
|
7
6
|
|
8
7
|
class Manual < ActiveRecord::Base
|
9
8
|
extend FriendlyId
|
10
|
-
friendly_id :name, :
|
9
|
+
friendly_id :name, use: [:slugged, :history]
|
11
10
|
end
|
12
11
|
|
13
12
|
def model_class
|
@@ -15,7 +14,7 @@ class HistoryTest < TestCaseClass
|
|
15
14
|
end
|
16
15
|
|
17
16
|
test "should insert record in slugs table on create" do
|
18
|
-
with_instance_of(model_class) {|record| assert record.slugs.any?}
|
17
|
+
with_instance_of(model_class) { |record| assert record.slugs.any? }
|
19
18
|
end
|
20
19
|
|
21
20
|
test "should not create new slug record if friendly_id is not changed" do
|
@@ -52,8 +51,9 @@ class HistoryTest < TestCaseClass
|
|
52
51
|
|
53
52
|
test "should create slug records on each change" do
|
54
53
|
transaction do
|
55
|
-
|
54
|
+
model_class.create! name: "hello"
|
56
55
|
assert_equal 1, FriendlyId::Slug.count
|
56
|
+
|
57
57
|
record = model_class.friendly.find("hello")
|
58
58
|
record.name = "hello again"
|
59
59
|
record.slug = nil
|
@@ -65,7 +65,7 @@ class HistoryTest < TestCaseClass
|
|
65
65
|
test "should not be read only when found by slug" do
|
66
66
|
with_instance_of(model_class) do |record|
|
67
67
|
refute model_class.friendly.find(record.friendly_id).readonly?
|
68
|
-
assert record.update name:
|
68
|
+
assert record.update name: "foo"
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
@@ -80,21 +80,21 @@ class HistoryTest < TestCaseClass
|
|
80
80
|
|
81
81
|
test "should handle renames" do
|
82
82
|
with_instance_of(model_class) do |record|
|
83
|
-
record.name =
|
83
|
+
record.name = "x"
|
84
84
|
record.slug = nil
|
85
85
|
assert record.save
|
86
|
-
record.name =
|
86
|
+
record.name = "y"
|
87
87
|
record.slug = nil
|
88
88
|
assert record.save
|
89
|
-
record.name =
|
89
|
+
record.name = "x"
|
90
90
|
record.slug = nil
|
91
91
|
assert record.save
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
test
|
95
|
+
test "should maintain history even if current slug is not the most recent one" do
|
96
96
|
with_instance_of(model_class) do |record|
|
97
|
-
record.name =
|
97
|
+
record.name = "current"
|
98
98
|
assert record.save
|
99
99
|
|
100
100
|
# this feels like a hack. only thing i can get to work with the HistoryTestWithSti
|
@@ -103,8 +103,8 @@ class HistoryTest < TestCaseClass
|
|
103
103
|
# create several slugs for record
|
104
104
|
# current slug does not have max id
|
105
105
|
FriendlyId::Slug.delete_all
|
106
|
-
FriendlyId::Slug.create(sluggable_type: sluggable_type, sluggable_id: record.id, slug:
|
107
|
-
FriendlyId::Slug.create(sluggable_type: sluggable_type, sluggable_id: record.id, slug:
|
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
108
|
|
109
109
|
record.reload
|
110
110
|
record.slug = nil
|
@@ -116,24 +116,24 @@ class HistoryTest < TestCaseClass
|
|
116
116
|
|
117
117
|
test "should not create new slugs that match old slugs" do
|
118
118
|
transaction do
|
119
|
-
first_record = model_class.create! :
|
119
|
+
first_record = model_class.create! name: "foo"
|
120
120
|
first_record.name = "bar"
|
121
121
|
first_record.save!
|
122
|
-
second_record = model_class.create! :
|
122
|
+
second_record = model_class.create! name: "foo"
|
123
123
|
assert second_record.slug != "foo"
|
124
124
|
assert_match(/foo-.+/, second_record.slug)
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
|
-
test
|
128
|
+
test "should not fail when updating historic slugs" do
|
129
129
|
transaction do
|
130
|
-
first_record = model_class.create! :
|
131
|
-
second_record = model_class.create! :
|
130
|
+
first_record = model_class.create! name: "foo"
|
131
|
+
second_record = model_class.create! name: "another"
|
132
132
|
|
133
|
-
second_record.update :
|
133
|
+
second_record.update name: "foo", slug: nil
|
134
134
|
assert_match(/foo-.*/, second_record.slug)
|
135
135
|
|
136
|
-
first_record.update :
|
136
|
+
first_record.update name: "another", slug: nil
|
137
137
|
assert_match(/another-.*/, first_record.slug)
|
138
138
|
end
|
139
139
|
end
|
@@ -144,25 +144,23 @@ class HistoryTest < TestCaseClass
|
|
144
144
|
second_record = model_class.create! name: "bar"
|
145
145
|
|
146
146
|
first_record.update! slug: "not_foo"
|
147
|
-
second_record.update! slug: "foo" #now both records have used foo; second_record most recently
|
147
|
+
second_record.update! slug: "foo" # now both records have used foo; second_record most recently
|
148
148
|
second_record.update! slug: "not_bar"
|
149
149
|
|
150
150
|
assert_equal model_class.friendly.find("foo"), second_record
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
test
|
154
|
+
test "should name table according to prefix and suffix" do
|
155
155
|
transaction do
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
FriendlyId::Slug.table_name = without_prefix
|
165
|
-
end
|
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
|
166
164
|
end
|
167
165
|
end
|
168
166
|
end
|
@@ -170,7 +168,7 @@ end
|
|
170
168
|
class HistoryTestWithAutomaticSlugRegeneration < HistoryTest
|
171
169
|
class Manual < ActiveRecord::Base
|
172
170
|
extend FriendlyId
|
173
|
-
friendly_id :name, :
|
171
|
+
friendly_id :name, use: [:slugged, :history]
|
174
172
|
|
175
173
|
def should_generate_new_friendly_id?
|
176
174
|
slug.blank? or name_changed?
|
@@ -181,62 +179,61 @@ class HistoryTestWithAutomaticSlugRegeneration < HistoryTest
|
|
181
179
|
Manual
|
182
180
|
end
|
183
181
|
|
184
|
-
test
|
185
|
-
with_instance_of(model_class, name:
|
186
|
-
record.name =
|
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"
|
187
185
|
record.save!
|
188
|
-
assert_equal
|
189
|
-
record.name =
|
186
|
+
assert_equal "bar", record.friendly_id
|
187
|
+
record.name = "foo"
|
190
188
|
record.save!
|
191
|
-
assert_equal
|
189
|
+
assert_equal "foo", record.friendly_id
|
192
190
|
end
|
193
191
|
end
|
194
192
|
end
|
195
193
|
|
196
194
|
class DependentDestroyTest < TestCaseClass
|
197
|
-
|
198
195
|
include FriendlyId::Test
|
199
196
|
|
200
197
|
class FalseManual < ActiveRecord::Base
|
201
|
-
self.table_name =
|
198
|
+
self.table_name = "manuals"
|
202
199
|
|
203
200
|
extend FriendlyId
|
204
|
-
friendly_id :name, :
|
201
|
+
friendly_id :name, use: :history, dependent: false
|
205
202
|
end
|
206
203
|
|
207
204
|
class DefaultManual < ActiveRecord::Base
|
208
|
-
self.table_name =
|
205
|
+
self.table_name = "manuals"
|
209
206
|
|
210
207
|
extend FriendlyId
|
211
|
-
friendly_id :name, :
|
208
|
+
friendly_id :name, use: :history
|
212
209
|
end
|
213
210
|
|
214
|
-
test
|
211
|
+
test "should allow disabling of dependent destroy" do
|
215
212
|
transaction do
|
216
|
-
assert FriendlyId::Slug.find_by_slug(
|
217
|
-
l = FalseManual.create! :
|
218
|
-
assert FriendlyId::Slug.find_by_slug(
|
213
|
+
assert FriendlyId::Slug.find_by_slug("foo").nil?
|
214
|
+
l = FalseManual.create! name: "foo"
|
215
|
+
assert FriendlyId::Slug.find_by_slug("foo").present?
|
219
216
|
l.destroy
|
220
|
-
assert FriendlyId::Slug.find_by_slug(
|
217
|
+
assert FriendlyId::Slug.find_by_slug("foo").present?
|
221
218
|
end
|
222
219
|
end
|
223
220
|
|
224
|
-
test
|
221
|
+
test "should dependently destroy by default" do
|
225
222
|
transaction do
|
226
|
-
assert FriendlyId::Slug.find_by_slug(
|
227
|
-
l = DefaultManual.create! :
|
228
|
-
assert FriendlyId::Slug.find_by_slug(
|
223
|
+
assert FriendlyId::Slug.find_by_slug("baz").nil?
|
224
|
+
l = DefaultManual.create! name: "baz"
|
225
|
+
assert FriendlyId::Slug.find_by_slug("baz").present?
|
229
226
|
l.destroy
|
230
|
-
assert FriendlyId::Slug.find_by_slug(
|
227
|
+
assert FriendlyId::Slug.find_by_slug("baz").nil?
|
231
228
|
end
|
232
229
|
end
|
233
230
|
end
|
234
231
|
|
235
|
-
if ActiveRecord::VERSION::STRING >=
|
232
|
+
if ActiveRecord::VERSION::STRING >= "5.0"
|
236
233
|
class HistoryTestWithParanoidDeletes < HistoryTest
|
237
234
|
class ParanoidRecord < ActiveRecord::Base
|
238
235
|
extend FriendlyId
|
239
|
-
friendly_id :name, :
|
236
|
+
friendly_id :name, use: :history, dependent: false
|
240
237
|
|
241
238
|
default_scope { where(deleted_at: nil) }
|
242
239
|
end
|
@@ -245,19 +242,19 @@ if ActiveRecord::VERSION::STRING >= '5.0'
|
|
245
242
|
ParanoidRecord
|
246
243
|
end
|
247
244
|
|
248
|
-
test
|
245
|
+
test "slug should have a sluggable even when soft deleted by a library" do
|
249
246
|
transaction do
|
250
|
-
assert FriendlyId::Slug.find_by_slug(
|
251
|
-
record = model_class.create(name:
|
252
|
-
assert FriendlyId::Slug.find_by_slug(
|
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?
|
253
250
|
|
254
251
|
record.update deleted_at: Time.now
|
255
252
|
|
256
|
-
orphan_slug = FriendlyId::Slug.find_by_slug(
|
257
|
-
assert orphan_slug.present?,
|
253
|
+
orphan_slug = FriendlyId::Slug.find_by_slug("paranoid")
|
254
|
+
assert orphan_slug.present?, "Orphaned slug should exist"
|
258
255
|
|
259
256
|
assert orphan_slug.valid?, "Errors: #{orphan_slug.errors.full_messages}"
|
260
|
-
assert orphan_slug.sluggable.present?,
|
257
|
+
assert orphan_slug.sluggable.present?, "Orphaned slug should still find corresponding paranoid sluggable"
|
261
258
|
end
|
262
259
|
end
|
263
260
|
end
|
@@ -266,7 +263,7 @@ end
|
|
266
263
|
class HistoryTestWithSti < HistoryTest
|
267
264
|
class Journalist < ActiveRecord::Base
|
268
265
|
extend FriendlyId
|
269
|
-
friendly_id :name, :
|
266
|
+
friendly_id :name, use: [:slugged, :history]
|
270
267
|
end
|
271
268
|
|
272
269
|
class Editorialist < Journalist
|
@@ -280,16 +277,15 @@ end
|
|
280
277
|
class HistoryTestWithFriendlyFinders < HistoryTest
|
281
278
|
class Journalist < ActiveRecord::Base
|
282
279
|
extend FriendlyId
|
283
|
-
friendly_id :name, :
|
280
|
+
friendly_id :name, use: [:slugged, :finders, :history]
|
284
281
|
end
|
285
282
|
|
286
283
|
class Restaurant < ActiveRecord::Base
|
287
284
|
extend FriendlyId
|
288
285
|
belongs_to :city
|
289
|
-
friendly_id :name, :
|
286
|
+
friendly_id :name, use: [:slugged, :history, :finders]
|
290
287
|
end
|
291
288
|
|
292
|
-
|
293
289
|
test "should be findable by old slugs" do
|
294
290
|
[Journalist, Restaurant].each do |model_class|
|
295
291
|
with_instance_of(model_class) do |record|
|
@@ -318,7 +314,7 @@ class HistoryTestWithFindersBeforeHistory < HistoryTest
|
|
318
314
|
|
319
315
|
belongs_to :novelist
|
320
316
|
|
321
|
-
friendly_id :name, :
|
317
|
+
friendly_id :name, use: [:finders, :history]
|
322
318
|
|
323
319
|
def should_generate_new_friendly_id?
|
324
320
|
slug.blank? || name_changed?
|
@@ -327,8 +323,8 @@ class HistoryTestWithFindersBeforeHistory < HistoryTest
|
|
327
323
|
|
328
324
|
test "should be findable by old slug through has_many association" do
|
329
325
|
transaction do
|
330
|
-
novelist = Novelist.create!(:
|
331
|
-
novel = novelist.novels.create(:
|
326
|
+
novelist = Novelist.create!(name: "Stephen King")
|
327
|
+
novel = novelist.novels.create(name: "Rita Hayworth and Shawshank Redemption")
|
332
328
|
slug = novel.slug
|
333
329
|
novel.name = "Shawshank Redemption"
|
334
330
|
novel.save!
|
@@ -345,7 +341,7 @@ end
|
|
345
341
|
class Restaurant < ActiveRecord::Base
|
346
342
|
extend FriendlyId
|
347
343
|
belongs_to :city
|
348
|
-
friendly_id :name, :
|
344
|
+
friendly_id :name, use: [:scoped, :history], scope: :city
|
349
345
|
end
|
350
346
|
|
351
347
|
class ScopedHistoryTest < TestCaseClass
|
@@ -389,10 +385,10 @@ class ScopedHistoryTest < TestCaseClass
|
|
389
385
|
record.slug = nil
|
390
386
|
record.save!
|
391
387
|
|
392
|
-
second_record = model_class.create! :
|
388
|
+
second_record = model_class.create! city: city, name: "x"
|
393
389
|
assert_match(/x-.+/, second_record.friendly_id)
|
394
390
|
|
395
|
-
third_record = model_class.create! :
|
391
|
+
third_record = model_class.create! city: city, name: "y"
|
396
392
|
assert_match(/y-.+/, third_record.friendly_id)
|
397
393
|
end
|
398
394
|
end
|
@@ -429,8 +425,8 @@ class ScopedHistoryTest < TestCaseClass
|
|
429
425
|
transaction do
|
430
426
|
city = City.create!
|
431
427
|
second_city = City.create!
|
432
|
-
record = model_class.create! :
|
433
|
-
second_record = model_class.create! :
|
428
|
+
record = model_class.create! city: city, name: "x"
|
429
|
+
second_record = model_class.create! city: second_city, name: "x"
|
434
430
|
|
435
431
|
assert_equal record.slug, second_record.slug
|
436
432
|
end
|
data/test/numeric_slug_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "helper"
|
2
2
|
|
3
3
|
class NumericSlugTest < TestCaseClass
|
4
4
|
include FriendlyId::Test
|
@@ -10,21 +10,21 @@ class NumericSlugTest < TestCaseClass
|
|
10
10
|
|
11
11
|
test "should generate numeric slugs" do
|
12
12
|
transaction do
|
13
|
-
record = model_class.create! :
|
13
|
+
record = model_class.create! name: "123"
|
14
14
|
assert_equal "123", record.slug
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
test "should find by numeric slug" do
|
19
19
|
transaction do
|
20
|
-
record = model_class.create! :
|
20
|
+
record = model_class.create! name: "123"
|
21
21
|
assert_equal model_class.friendly.find("123").id, record.id
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
test "should exist? by numeric slug" do
|
26
26
|
transaction do
|
27
|
-
|
27
|
+
model_class.create! name: "123"
|
28
28
|
assert model_class.friendly.exists?("123")
|
29
29
|
end
|
30
30
|
end
|
data/test/object_utils_test.rb
CHANGED
data/test/reserved_test.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
require "helper"
|
2
2
|
|
3
3
|
class ReservedTest < TestCaseClass
|
4
|
-
|
5
4
|
include FriendlyId::Test
|
6
5
|
|
7
6
|
class Journalist < ActiveRecord::Base
|
8
7
|
extend FriendlyId
|
9
|
-
friendly_id :slug_candidates, :
|
8
|
+
friendly_id :slug_candidates, use: [:slugged, :reserved], reserved_words: %w[new edit]
|
10
9
|
|
11
10
|
after_validation :move_friendly_id_error_to_name
|
12
11
|
|
@@ -24,9 +23,9 @@ class ReservedTest < TestCaseClass
|
|
24
23
|
end
|
25
24
|
|
26
25
|
test "should reserve words" do
|
27
|
-
%w
|
26
|
+
%w[new edit NEW Edit].each do |word|
|
28
27
|
transaction do
|
29
|
-
assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :
|
28
|
+
assert_raises(ActiveRecord::RecordInvalid) { model_class.create! name: word }
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
@@ -43,7 +42,7 @@ class ReservedTest < TestCaseClass
|
|
43
42
|
|
44
43
|
test "should reject reserved candidates" do
|
45
44
|
transaction do
|
46
|
-
record = model_class.new(:
|
45
|
+
record = model_class.new(name: "new")
|
47
46
|
def record.slug_candidates
|
48
47
|
[:name, "foo"]
|
49
48
|
end
|
@@ -54,22 +53,21 @@ class ReservedTest < TestCaseClass
|
|
54
53
|
|
55
54
|
test "should be invalid if all candidates are reserved" do
|
56
55
|
transaction do
|
57
|
-
record = model_class.new(:
|
56
|
+
record = model_class.new(name: "new")
|
58
57
|
def record.slug_candidates
|
59
58
|
["edit", "new"]
|
60
59
|
end
|
61
|
-
assert_raises(ActiveRecord::RecordInvalid) {record.save!}
|
60
|
+
assert_raises(ActiveRecord::RecordInvalid) { record.save! }
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
64
|
test "should optionally treat reserved words as conflict" do
|
66
65
|
klass = Class.new(model_class) do
|
67
|
-
friendly_id :slug_candidates, :
|
66
|
+
friendly_id :slug_candidates, use: [:slugged, :reserved], reserved_words: %w[new edit], treat_reserved_as_conflict: true
|
68
67
|
end
|
69
68
|
|
70
|
-
with_instance_of(klass, name:
|
71
|
-
assert_match(/new-([0-9a-z]
|
69
|
+
with_instance_of(klass, name: "new") do |record|
|
70
|
+
assert_match(/new-([0-9a-z]+-){4}[0-9a-z]+\z/, record.slug)
|
72
71
|
end
|
73
72
|
end
|
74
|
-
|
75
73
|
end
|
data/test/schema.rb
CHANGED
@@ -25,7 +25,7 @@ module FriendlyId
|
|
25
25
|
|
26
26
|
tables.each do |table_name|
|
27
27
|
create_table table_name do |t|
|
28
|
-
t.string
|
28
|
+
t.string :name
|
29
29
|
t.boolean :active
|
30
30
|
end
|
31
31
|
end
|
@@ -41,7 +41,7 @@ module FriendlyId
|
|
41
41
|
|
42
42
|
slugged_tables.each do |table_name|
|
43
43
|
add_column table_name, :slug, :string
|
44
|
-
add_index
|
44
|
+
add_index table_name, :slug, unique: true if table_name != "novels"
|
45
45
|
end
|
46
46
|
|
47
47
|
scoped_tables.each do |table_name|
|
@@ -57,7 +57,7 @@ module FriendlyId
|
|
57
57
|
# This will be used to test scopes
|
58
58
|
add_column :novels, :novelist_id, :integer
|
59
59
|
add_column :novels, :publisher_id, :integer
|
60
|
-
add_index :novels, [:slug, :publisher_id, :novelist_id], :
|
60
|
+
add_index :novels, [:slug, :publisher_id, :novelist_id], unique: true
|
61
61
|
|
62
62
|
# This will be used to test column name quoting
|
63
63
|
add_column :journalists, "strange name", :string
|
@@ -69,6 +69,7 @@ module FriendlyId
|
|
69
69
|
add_column :journalists, "slug_en", :string
|
70
70
|
add_column :journalists, "slug_es", :string
|
71
71
|
add_column :journalists, "slug_de", :string
|
72
|
+
add_column :journalists, "slug_fr_ca", :string
|
72
73
|
|
73
74
|
# This will be used to test relationships
|
74
75
|
add_column :books, :author_id, :integer
|
@@ -77,7 +78,7 @@ module FriendlyId
|
|
77
78
|
add_column :restaurants, :city_id, :integer
|
78
79
|
|
79
80
|
# Used to test candidates
|
80
|
-
add_column :cities, :code, :string, :
|
81
|
+
add_column :cities, :code, :string, limit: 3
|
81
82
|
|
82
83
|
# Used as a non-default slug_column
|
83
84
|
add_column :authors, :subdomain, :string
|
data/test/scoped_test.rb
CHANGED
@@ -2,14 +2,14 @@ require "helper"
|
|
2
2
|
|
3
3
|
class Novelist < ActiveRecord::Base
|
4
4
|
extend FriendlyId
|
5
|
-
friendly_id :name, :
|
5
|
+
friendly_id :name, use: :slugged
|
6
6
|
end
|
7
7
|
|
8
8
|
class Novel < ActiveRecord::Base
|
9
9
|
extend FriendlyId
|
10
10
|
belongs_to :novelist
|
11
11
|
belongs_to :publisher
|
12
|
-
friendly_id :name, :
|
12
|
+
friendly_id :name, use: :scoped, scope: [:publisher, :novelist]
|
13
13
|
|
14
14
|
def should_generate_new_friendly_id?
|
15
15
|
new_record? || super
|
@@ -21,7 +21,6 @@ class Publisher < ActiveRecord::Base
|
|
21
21
|
end
|
22
22
|
|
23
23
|
class ScopedTest < TestCaseClass
|
24
|
-
|
25
24
|
include FriendlyId::Test
|
26
25
|
include FriendlyId::Test::Shared::Core
|
27
26
|
|
@@ -37,42 +36,42 @@ class ScopedTest < TestCaseClass
|
|
37
36
|
model_class = Class.new(ActiveRecord::Base) do
|
38
37
|
self.abstract_class = true
|
39
38
|
extend FriendlyId
|
40
|
-
friendly_id :empty, :
|
39
|
+
friendly_id :empty, use: :scoped, scope: :dummy
|
41
40
|
end
|
42
41
|
assert_equal ["dummy"], model_class.friendly_id_config.scope_columns
|
43
42
|
end
|
44
43
|
|
45
44
|
test "should allow duplicate slugs outside scope" do
|
46
45
|
transaction do
|
47
|
-
novel1 = Novel.create! :
|
48
|
-
novel2 = Novel.create! :
|
46
|
+
novel1 = Novel.create! name: "a", novelist: Novelist.create!(name: "a")
|
47
|
+
novel2 = Novel.create! name: "a", novelist: Novelist.create!(name: "b")
|
49
48
|
assert_equal novel1.friendly_id, novel2.friendly_id
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
53
52
|
test "should not allow duplicate slugs inside scope" do
|
54
53
|
with_instance_of Novelist do |novelist|
|
55
|
-
novel1 = Novel.create! :
|
56
|
-
novel2 = Novel.create! :
|
54
|
+
novel1 = Novel.create! name: "a", novelist: novelist
|
55
|
+
novel2 = Novel.create! name: "a", novelist: novelist
|
57
56
|
assert novel1.friendly_id != novel2.friendly_id
|
58
57
|
end
|
59
58
|
end
|
60
59
|
|
61
60
|
test "should apply scope with multiple columns" do
|
62
61
|
transaction do
|
63
|
-
novelist = Novelist.create! :
|
64
|
-
publisher = Publisher.create! :
|
65
|
-
novel1 = Novel.create! :
|
66
|
-
novel2 = Novel.create! :
|
67
|
-
novel3 = Novel.create! :
|
68
|
-
novel4 = Novel.create! :
|
62
|
+
novelist = Novelist.create! name: "a"
|
63
|
+
publisher = Publisher.create! name: "b"
|
64
|
+
novel1 = Novel.create! name: "c", novelist: novelist, publisher: publisher
|
65
|
+
novel2 = Novel.create! name: "c", novelist: novelist, publisher: Publisher.create(name: "d")
|
66
|
+
novel3 = Novel.create! name: "c", novelist: Novelist.create(name: "e"), publisher: publisher
|
67
|
+
novel4 = Novel.create! name: "c", novelist: novelist, publisher: publisher
|
69
68
|
assert_equal novel1.friendly_id, novel2.friendly_id
|
70
69
|
assert_equal novel2.friendly_id, novel3.friendly_id
|
71
70
|
assert novel3.friendly_id != novel4.friendly_id
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
|
-
test
|
74
|
+
test "should allow a record to reuse its own slug" do
|
76
75
|
with_instance_of(model_class) do |record|
|
77
76
|
old_id = record.friendly_id
|
78
77
|
record.slug = nil
|
@@ -83,15 +82,14 @@ class ScopedTest < TestCaseClass
|
|
83
82
|
|
84
83
|
test "should generate new slug when scope changes" do
|
85
84
|
transaction do
|
86
|
-
novelist = Novelist.create! :
|
87
|
-
publisher = Publisher.create! :
|
88
|
-
novel1 = Novel.create! :
|
89
|
-
novel2 = Novel.create! :
|
85
|
+
novelist = Novelist.create! name: "a"
|
86
|
+
publisher = Publisher.create! name: "b"
|
87
|
+
novel1 = Novel.create! name: "c", novelist: novelist, publisher: publisher
|
88
|
+
novel2 = Novel.create! name: "c", novelist: novelist, publisher: Publisher.create(name: "d")
|
90
89
|
assert_equal novel1.friendly_id, novel2.friendly_id
|
91
90
|
novel2.publisher = publisher
|
92
91
|
novel2.save!
|
93
92
|
assert novel2.friendly_id != novel1.friendly_id
|
94
93
|
end
|
95
94
|
end
|
96
|
-
|
97
95
|
end
|