friendly_id 5.2.4 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/dependabot.yml +6 -0
  5. data/.github/stale.yml +17 -0
  6. data/.github/workflows/test.yml +58 -0
  7. data/Changelog.md +41 -0
  8. data/Gemfile +10 -11
  9. data/README.md +42 -15
  10. data/Rakefile +24 -27
  11. data/bench.rb +30 -27
  12. data/certs/parndt.pem +27 -0
  13. data/friendly_id.gemspec +28 -27
  14. data/gemfiles/Gemfile.rails-5.2.rb +11 -16
  15. data/gemfiles/Gemfile.rails-6.0.rb +22 -0
  16. data/gemfiles/Gemfile.rails-6.1.rb +22 -0
  17. data/gemfiles/Gemfile.rails-7.0.rb +22 -0
  18. data/guide.rb +5 -5
  19. data/lib/friendly_id/base.rb +61 -68
  20. data/lib/friendly_id/candidates.rb +9 -11
  21. data/lib/friendly_id/configuration.rb +8 -8
  22. data/lib/friendly_id/finder_methods.rb +72 -13
  23. data/lib/friendly_id/finders.rb +64 -67
  24. data/lib/friendly_id/history.rb +72 -66
  25. data/lib/friendly_id/initializer.rb +5 -5
  26. data/lib/friendly_id/migration.rb +10 -11
  27. data/lib/friendly_id/object_utils.rb +2 -2
  28. data/lib/friendly_id/reserved.rb +28 -32
  29. data/lib/friendly_id/scoped.rb +105 -103
  30. data/lib/friendly_id/sequentially_slugged/calculator.rb +69 -0
  31. data/lib/friendly_id/sequentially_slugged.rb +21 -58
  32. data/lib/friendly_id/simple_i18n.rb +75 -69
  33. data/lib/friendly_id/slug.rb +1 -2
  34. data/lib/friendly_id/slug_generator.rb +1 -3
  35. data/lib/friendly_id/slugged.rb +236 -239
  36. data/lib/friendly_id/version.rb +1 -1
  37. data/lib/friendly_id.rb +41 -45
  38. data/lib/generators/friendly_id_generator.rb +9 -9
  39. data/test/base_test.rb +10 -13
  40. data/test/benchmarks/finders.rb +28 -26
  41. data/test/benchmarks/object_utils.rb +13 -13
  42. data/test/candidates_test.rb +17 -18
  43. data/test/configuration_test.rb +7 -11
  44. data/test/core_test.rb +1 -2
  45. data/test/databases.yml +7 -4
  46. data/test/finders_test.rb +52 -5
  47. data/test/generator_test.rb +16 -26
  48. data/test/helper.rb +33 -20
  49. data/test/history_test.rb +116 -72
  50. data/test/numeric_slug_test.rb +31 -0
  51. data/test/object_utils_test.rb +0 -2
  52. data/test/reserved_test.rb +9 -11
  53. data/test/schema.rb +5 -4
  54. data/test/scoped_test.rb +26 -15
  55. data/test/sequentially_slugged_test.rb +107 -33
  56. data/test/shared.rb +17 -18
  57. data/test/simple_i18n_test.rb +23 -13
  58. data/test/slugged_test.rb +254 -78
  59. data/test/sti_test.rb +19 -21
  60. data.tar.gz.sig +0 -0
  61. metadata +49 -19
  62. metadata.gz.sig +1 -0
  63. data/.travis.yml +0 -57
  64. data/gemfiles/Gemfile.rails-4.0.rb +0 -30
  65. data/gemfiles/Gemfile.rails-4.1.rb +0 -29
  66. data/gemfiles/Gemfile.rails-4.2.rb +0 -28
  67. data/gemfiles/Gemfile.rails-5.0.rb +0 -28
  68. data/gemfiles/Gemfile.rails-5.1.rb +0 -27
data/test/helper.rb CHANGED
@@ -1,21 +1,21 @@
1
1
  require "bundler/setup"
2
2
 
3
- if ENV['COVERALLS'] || ENV['COVERAGE']
4
- require 'simplecov'
5
- if ENV['COVERALLS']
6
- require 'coveralls'
3
+ if ENV["COVERALLS"] || ENV["COVERAGE"]
4
+ require "simplecov"
5
+ if ENV["COVERALLS"]
6
+ require "coveralls"
7
7
  SimpleCov.formatter = Coveralls::SimpleCov::Formatter
8
8
  end
9
9
  SimpleCov.start do
10
- add_filter 'test'
11
- add_filter 'friendly_id/migration'
10
+ add_filter "test"
11
+ add_filter "friendly_id/migration"
12
12
  end
13
13
  end
14
14
 
15
15
  begin
16
- require 'minitest'
16
+ require "minitest"
17
17
  rescue LoadError
18
- require 'minitest/unit'
18
+ require "minitest/unit"
19
19
  end
20
20
 
21
21
  begin
@@ -24,9 +24,10 @@ rescue NameError
24
24
  TestCaseClass = MiniTest::Unit::TestCase
25
25
  end
26
26
 
27
- require "mocha/setup"
27
+ require "mocha/minitest"
28
28
  require "active_record"
29
- require 'active_support/core_ext/time/conversions'
29
+ require "active_support/core_ext/time/conversions"
30
+ require "erb"
30
31
 
31
32
  I18n.enforce_available_locales = false
32
33
 
@@ -38,29 +39,32 @@ if ENV["LOG"]
38
39
  ActiveRecord::Base.logger = Logger.new($stdout)
39
40
  end
40
41
 
41
- if ActiveSupport::VERSION::STRING >= '4.2'
42
+ if ActiveSupport::VERSION::STRING >= "4.2"
42
43
  ActiveSupport.test_order = :random
43
44
  end
44
45
 
45
46
  module FriendlyId
46
47
  module Test
47
-
48
48
  def self.included(base)
49
49
  if Minitest.respond_to?(:autorun)
50
50
  Minitest.autorun
51
51
  else
52
- require 'minitest/autorun'
52
+ require "minitest/autorun"
53
53
  end
54
54
  rescue LoadError
55
55
  end
56
56
 
57
57
  def transaction
58
- ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
58
+ ActiveRecord::Base.transaction do
59
+ yield
60
+
61
+ raise ActiveRecord::Rollback
62
+ end
59
63
  end
60
64
 
61
65
  def with_instance_of(*args)
62
66
  model_class = args.shift
63
- args[0] ||= {:name => "a b c"}
67
+ args[0] ||= {name: "a b c"}
64
68
  transaction { yield model_class.create!(*args) }
65
69
  end
66
70
 
@@ -69,8 +73,11 @@ module FriendlyId
69
73
 
70
74
  def connect
71
75
  version = ActiveRecord::VERSION::STRING
72
- driver = FriendlyId::Test::Database.driver
73
- engine = RUBY_ENGINE rescue "ruby"
76
+ engine = begin
77
+ RUBY_ENGINE
78
+ rescue
79
+ "ruby"
80
+ end
74
81
 
75
82
  ActiveRecord::Base.establish_connection config[driver]
76
83
  message = "Using #{engine} #{RUBY_VERSION} AR #{version} with #{driver}"
@@ -86,11 +93,17 @@ module FriendlyId
86
93
  end
87
94
 
88
95
  def config
89
- @config ||= YAML::load(File.open(File.expand_path("../databases.yml", __FILE__)))
96
+ @config ||= YAML.safe_load(
97
+ ERB.new(
98
+ File.read(File.expand_path("../databases.yml", __FILE__))
99
+ ).result
100
+ )
90
101
  end
91
102
 
92
103
  def driver
93
- (ENV["DB"] or "sqlite3").downcase
104
+ db_driver = ENV.fetch("DB", "sqlite3").downcase
105
+ db_driver = "postgres" if %w[postgresql pg].include?(db_driver)
106
+ db_driver
94
107
  end
95
108
 
96
109
  def in_memory?
@@ -109,4 +122,4 @@ end
109
122
  require "schema"
110
123
  require "shared"
111
124
  FriendlyId::Test::Database.connect
112
- at_exit {ActiveRecord::Base.connection.disconnect!}
125
+ at_exit { ActiveRecord::Base.connection.disconnect! }
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, :use => [:slugged, :history]
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
- record = model_class.create! :name => "hello"
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,8 +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_attribute :name, 'foo'
69
- assert record.update_attributes name: 'foo'
68
+ assert record.update name: "foo"
70
69
  end
71
70
  end
72
71
 
@@ -81,38 +80,60 @@ class HistoryTest < TestCaseClass
81
80
 
82
81
  test "should handle renames" do
83
82
  with_instance_of(model_class) do |record|
84
- record.name = 'x'
83
+ record.name = "x"
85
84
  record.slug = nil
86
85
  assert record.save
87
- record.name = 'y'
86
+ record.name = "y"
88
87
  record.slug = nil
89
88
  assert record.save
90
- record.name = 'x'
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
91
110
  record.slug = nil
92
111
  assert record.save
112
+
113
+ assert_equal 2, FriendlyId::Slug.count
93
114
  end
94
115
  end
95
116
 
96
117
  test "should not create new slugs that match old slugs" do
97
118
  transaction do
98
- first_record = model_class.create! :name => "foo"
119
+ first_record = model_class.create! name: "foo"
99
120
  first_record.name = "bar"
100
121
  first_record.save!
101
- second_record = model_class.create! :name => "foo"
122
+ second_record = model_class.create! name: "foo"
102
123
  assert second_record.slug != "foo"
103
124
  assert_match(/foo-.+/, second_record.slug)
104
125
  end
105
126
  end
106
127
 
107
- test 'should not fail when updating historic slugs' do
128
+ test "should not fail when updating historic slugs" do
108
129
  transaction do
109
- first_record = model_class.create! :name => "foo"
110
- second_record = model_class.create! :name => 'another'
130
+ first_record = model_class.create! name: "foo"
131
+ second_record = model_class.create! name: "another"
111
132
 
112
- second_record.update_attributes :name => 'foo', :slug => nil
133
+ second_record.update name: "foo", slug: nil
113
134
  assert_match(/foo-.*/, second_record.slug)
114
135
 
115
- first_record.update_attributes :name => 'another', :slug => nil
136
+ first_record.update name: "another", slug: nil
116
137
  assert_match(/another-.*/, first_record.slug)
117
138
  end
118
139
  end
@@ -123,25 +144,23 @@ class HistoryTest < TestCaseClass
123
144
  second_record = model_class.create! name: "bar"
124
145
 
125
146
  first_record.update! slug: "not_foo"
126
- 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
127
148
  second_record.update! slug: "not_bar"
128
149
 
129
150
  assert_equal model_class.friendly.find("foo"), second_record
130
151
  end
131
152
  end
132
153
 
133
- test 'should name table according to prefix and suffix' do
154
+ test "should name table according to prefix and suffix" do
134
155
  transaction do
135
- begin
136
- prefix = "prefix_"
137
- without_prefix = FriendlyId::Slug.table_name
138
- ActiveRecord::Base.table_name_prefix = prefix
139
- FriendlyId::Slug.reset_table_name
140
- assert_equal prefix + without_prefix, FriendlyId::Slug.table_name
141
- ensure
142
- ActiveRecord::Base.table_name_prefix = ""
143
- FriendlyId::Slug.table_name = without_prefix
144
- 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
145
164
  end
146
165
  end
147
166
  end
@@ -149,7 +168,7 @@ end
149
168
  class HistoryTestWithAutomaticSlugRegeneration < HistoryTest
150
169
  class Manual < ActiveRecord::Base
151
170
  extend FriendlyId
152
- friendly_id :name, :use => [:slugged, :history]
171
+ friendly_id :name, use: [:slugged, :history]
153
172
 
154
173
  def should_generate_new_friendly_id?
155
174
  slug.blank? or name_changed?
@@ -160,62 +179,61 @@ class HistoryTestWithAutomaticSlugRegeneration < HistoryTest
160
179
  Manual
161
180
  end
162
181
 
163
- test 'should allow reversion back to a previously used slug' do
164
- with_instance_of(model_class, name: 'foo') do |record|
165
- record.name = 'bar'
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"
166
185
  record.save!
167
- assert_equal 'bar', record.friendly_id
168
- record.name = 'foo'
186
+ assert_equal "bar", record.friendly_id
187
+ record.name = "foo"
169
188
  record.save!
170
- assert_equal 'foo', record.friendly_id
189
+ assert_equal "foo", record.friendly_id
171
190
  end
172
191
  end
173
192
  end
174
193
 
175
194
  class DependentDestroyTest < TestCaseClass
176
-
177
195
  include FriendlyId::Test
178
196
 
179
197
  class FalseManual < ActiveRecord::Base
180
- self.table_name = 'manuals'
198
+ self.table_name = "manuals"
181
199
 
182
200
  extend FriendlyId
183
- friendly_id :name, :use => :history, :dependent => false
201
+ friendly_id :name, use: :history, dependent: false
184
202
  end
185
203
 
186
204
  class DefaultManual < ActiveRecord::Base
187
- self.table_name = 'manuals'
205
+ self.table_name = "manuals"
188
206
 
189
207
  extend FriendlyId
190
- friendly_id :name, :use => :history
208
+ friendly_id :name, use: :history
191
209
  end
192
210
 
193
- test 'should allow disabling of dependent destroy' do
211
+ test "should allow disabling of dependent destroy" do
194
212
  transaction do
195
- assert FriendlyId::Slug.find_by_slug('foo').nil?
196
- l = FalseManual.create! :name => 'foo'
197
- assert FriendlyId::Slug.find_by_slug('foo').present?
213
+ assert FriendlyId::Slug.find_by_slug("foo").nil?
214
+ l = FalseManual.create! name: "foo"
215
+ assert FriendlyId::Slug.find_by_slug("foo").present?
198
216
  l.destroy
199
- assert FriendlyId::Slug.find_by_slug('foo').present?
217
+ assert FriendlyId::Slug.find_by_slug("foo").present?
200
218
  end
201
219
  end
202
220
 
203
- test 'should dependently destroy by default' do
221
+ test "should dependently destroy by default" do
204
222
  transaction do
205
- assert FriendlyId::Slug.find_by_slug('baz').nil?
206
- l = DefaultManual.create! :name => 'baz'
207
- assert FriendlyId::Slug.find_by_slug('baz').present?
223
+ assert FriendlyId::Slug.find_by_slug("baz").nil?
224
+ l = DefaultManual.create! name: "baz"
225
+ assert FriendlyId::Slug.find_by_slug("baz").present?
208
226
  l.destroy
209
- assert FriendlyId::Slug.find_by_slug('baz').nil?
227
+ assert FriendlyId::Slug.find_by_slug("baz").nil?
210
228
  end
211
229
  end
212
230
  end
213
231
 
214
- if ActiveRecord::VERSION::STRING >= '5.0'
232
+ if ActiveRecord::VERSION::STRING >= "5.0"
215
233
  class HistoryTestWithParanoidDeletes < HistoryTest
216
234
  class ParanoidRecord < ActiveRecord::Base
217
235
  extend FriendlyId
218
- friendly_id :name, :use => :history, :dependent => false
236
+ friendly_id :name, use: :history, dependent: false
219
237
 
220
238
  default_scope { where(deleted_at: nil) }
221
239
  end
@@ -224,19 +242,19 @@ if ActiveRecord::VERSION::STRING >= '5.0'
224
242
  ParanoidRecord
225
243
  end
226
244
 
227
- test 'slug should have a sluggable even when soft deleted by a library' do
245
+ test "slug should have a sluggable even when soft deleted by a library" do
228
246
  transaction do
229
- assert FriendlyId::Slug.find_by_slug('paranoid').nil?
230
- record = model_class.create(name: 'paranoid')
231
- assert FriendlyId::Slug.find_by_slug('paranoid').present?
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?
232
250
 
233
- record.update_attribute(:deleted_at, Time.now)
251
+ record.update deleted_at: Time.now
234
252
 
235
- orphan_slug = FriendlyId::Slug.find_by_slug('paranoid')
236
- assert orphan_slug.present?, 'Orphaned slug should exist'
253
+ orphan_slug = FriendlyId::Slug.find_by_slug("paranoid")
254
+ assert orphan_slug.present?, "Orphaned slug should exist"
237
255
 
238
256
  assert orphan_slug.valid?, "Errors: #{orphan_slug.errors.full_messages}"
239
- assert orphan_slug.sluggable.present?, 'Orphaned slug should still find corresponding paranoid sluggable'
257
+ assert orphan_slug.sluggable.present?, "Orphaned slug should still find corresponding paranoid sluggable"
240
258
  end
241
259
  end
242
260
  end
@@ -245,7 +263,7 @@ end
245
263
  class HistoryTestWithSti < HistoryTest
246
264
  class Journalist < ActiveRecord::Base
247
265
  extend FriendlyId
248
- friendly_id :name, :use => [:slugged, :history]
266
+ friendly_id :name, use: [:slugged, :history]
249
267
  end
250
268
 
251
269
  class Editorialist < Journalist
@@ -259,16 +277,15 @@ end
259
277
  class HistoryTestWithFriendlyFinders < HistoryTest
260
278
  class Journalist < ActiveRecord::Base
261
279
  extend FriendlyId
262
- friendly_id :name, :use => [:slugged, :finders, :history]
280
+ friendly_id :name, use: [:slugged, :finders, :history]
263
281
  end
264
282
 
265
283
  class Restaurant < ActiveRecord::Base
266
284
  extend FriendlyId
267
285
  belongs_to :city
268
- friendly_id :name, :use => [:slugged, :history, :finders]
286
+ friendly_id :name, use: [:slugged, :history, :finders]
269
287
  end
270
288
 
271
-
272
289
  test "should be findable by old slugs" do
273
290
  [Journalist, Restaurant].each do |model_class|
274
291
  with_instance_of(model_class) do |record|
@@ -297,7 +314,7 @@ class HistoryTestWithFindersBeforeHistory < HistoryTest
297
314
 
298
315
  belongs_to :novelist
299
316
 
300
- friendly_id :name, :use => [:finders, :history]
317
+ friendly_id :name, use: [:finders, :history]
301
318
 
302
319
  def should_generate_new_friendly_id?
303
320
  slug.blank? || name_changed?
@@ -306,8 +323,8 @@ class HistoryTestWithFindersBeforeHistory < HistoryTest
306
323
 
307
324
  test "should be findable by old slug through has_many association" do
308
325
  transaction do
309
- novelist = Novelist.create!(:name => "Stephen King")
310
- novel = novelist.novels.create(:name => "Rita Hayworth and Shawshank Redemption")
326
+ novelist = Novelist.create!(name: "Stephen King")
327
+ novel = novelist.novels.create(name: "Rita Hayworth and Shawshank Redemption")
311
328
  slug = novel.slug
312
329
  novel.name = "Shawshank Redemption"
313
330
  novel.save!
@@ -324,7 +341,7 @@ end
324
341
  class Restaurant < ActiveRecord::Base
325
342
  extend FriendlyId
326
343
  belongs_to :city
327
- friendly_id :name, :use => [:scoped, :history], :scope => :city
344
+ friendly_id :name, use: [:scoped, :history], scope: :city
328
345
  end
329
346
 
330
347
  class ScopedHistoryTest < TestCaseClass
@@ -368,21 +385,48 @@ class ScopedHistoryTest < TestCaseClass
368
385
  record.slug = nil
369
386
  record.save!
370
387
 
371
- second_record = model_class.create! :city => city, :name => 'x'
388
+ second_record = model_class.create! city: city, name: "x"
372
389
  assert_match(/x-.+/, second_record.friendly_id)
373
390
 
374
- third_record = model_class.create! :city => city, :name => 'y'
391
+ third_record = model_class.create! city: city, name: "y"
375
392
  assert_match(/y-.+/, third_record.friendly_id)
376
393
  end
377
394
  end
378
395
  end
379
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
+
380
424
  test "should allow equal slugs in different scopes" do
381
425
  transaction do
382
426
  city = City.create!
383
427
  second_city = City.create!
384
- record = model_class.create! :city => city, :name => 'x'
385
- second_record = model_class.create! :city => second_city, :name => 'x'
428
+ record = model_class.create! city: city, name: "x"
429
+ second_record = model_class.create! city: second_city, name: "x"
386
430
 
387
431
  assert_equal record.slug, second_record.slug
388
432
  end
@@ -0,0 +1,31 @@
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
@@ -1,8 +1,6 @@
1
1
  require "helper"
2
2
 
3
-
4
3
  class ObjectUtilsTest < TestCaseClass
5
-
6
4
  include FriendlyId::Test
7
5
 
8
6
  test "strings with letters are friendly_ids" do
@@ -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, :use => [:slugged, :reserved], :reserved_words => %w(new edit)
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(new edit NEW Edit).each do |word|
26
+ %w[new edit NEW Edit].each do |word|
28
27
  transaction do
29
- assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
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(:name => '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(:name => '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, :use => [:slugged, :reserved], :reserved_words => %w(new edit), :treat_reserved_as_conflict => true
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: 'new') do |record|
71
- assert_match(/new-([0-9a-z]+\-){4}[0-9a-z]+\z/, record.slug)
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 :name
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 table_name, :slug, :unique => true if 'novels' != table_name
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], :unique => true
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, :limit => 3
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