friendly_id 5.2.3 → 5.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/stale.yml +17 -0
  6. data/.github/workflows/test.yml +60 -0
  7. data/Changelog.md +43 -1
  8. data/Gemfile +3 -0
  9. data/README.md +61 -168
  10. data/Rakefile +2 -2
  11. data/UPGRADING.md +115 -0
  12. data/certs/parndt.pem +25 -0
  13. data/friendly_id.gemspec +7 -3
  14. data/gemfiles/{Gemfile.rails-4.2.rb → Gemfile.rails-5.2.rb} +4 -5
  15. data/gemfiles/{Gemfile.rails-4.1.rb → Gemfile.rails-6.0.rb} +5 -7
  16. data/lib/friendly_id/base.rb +4 -8
  17. data/lib/friendly_id/candidates.rb +0 -2
  18. data/lib/friendly_id/configuration.rb +3 -2
  19. data/lib/friendly_id/finder_methods.rb +18 -7
  20. data/lib/friendly_id/finders.rb +1 -1
  21. data/lib/friendly_id/history.rb +21 -12
  22. data/lib/friendly_id/initializer.rb +11 -0
  23. data/lib/friendly_id/migration.rb +9 -3
  24. data/lib/friendly_id/object_utils.rb +9 -2
  25. data/lib/friendly_id/scoped.rb +8 -1
  26. data/lib/friendly_id/sequentially_slugged.rb +12 -2
  27. data/lib/friendly_id/slug.rb +4 -0
  28. data/lib/friendly_id/slugged.rb +2 -2
  29. data/lib/friendly_id/version.rb +1 -1
  30. data/test/databases.yml +6 -4
  31. data/test/finders_test.rb +24 -0
  32. data/test/helper.rb +13 -3
  33. data/test/history_test.rb +86 -7
  34. data/test/numeric_slug_test.rb +31 -0
  35. data/test/object_utils_test.rb +2 -0
  36. data/test/schema.rb +19 -2
  37. data/test/scoped_test.rb +13 -0
  38. data/test/sequentially_slugged_test.rb +59 -0
  39. data/test/shared.rb +2 -2
  40. data/test/simple_i18n_test.rb +2 -2
  41. data/test/slugged_test.rb +168 -4
  42. metadata +44 -16
  43. metadata.gz.sig +0 -0
  44. data/.travis.yml +0 -40
  45. data/gemfiles/Gemfile.rails-4.0.rb +0 -30
  46. data/gemfiles/Gemfile.rails-5.0.rb +0 -28
@@ -2,7 +2,14 @@ require "friendly_id/migration"
2
2
 
3
3
  module FriendlyId
4
4
  module Test
5
- class Schema < ActiveRecord::Migration
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
6
13
  class << self
7
14
  def down
8
15
  CreateFriendlyIdSlugs.down
@@ -41,6 +48,12 @@ module FriendlyId
41
48
  add_column table_name, :slug, :string
42
49
  end
43
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
+
44
57
  # This will be used to test scopes
45
58
  add_column :novels, :novelist_id, :integer
46
59
  add_column :novels, :publisher_id, :integer
@@ -78,6 +91,10 @@ module FriendlyId
78
91
  %w[journalists articles novelists novels manuals cities]
79
92
  end
80
93
 
94
+ def paranoid_tables
95
+ ["paranoid_records"]
96
+ end
97
+
81
98
  def tables_with_uuid_primary_key
82
99
  ["menu_items"]
83
100
  end
@@ -91,7 +108,7 @@ module FriendlyId
91
108
  end
92
109
 
93
110
  def tables
94
- simple_tables + slugged_tables + scoped_tables
111
+ simple_tables + slugged_tables + scoped_tables + paranoid_tables
95
112
  end
96
113
  end
97
114
  end
@@ -81,4 +81,17 @@ class ScopedTest < TestCaseClass
81
81
  end
82
82
  end
83
83
 
84
+ test "should generate new slug when scope changes" do
85
+ transaction do
86
+ novelist = Novelist.create! :name => "a"
87
+ publisher = Publisher.create! :name => "b"
88
+ novel1 = Novel.create! :name => "c", :novelist => novelist, :publisher => publisher
89
+ novel2 = Novel.create! :name => "c", :novelist => novelist, :publisher => Publisher.create(:name => "d")
90
+ assert_equal novel1.friendly_id, novel2.friendly_id
91
+ novel2.publisher = publisher
92
+ novel2.save!
93
+ assert novel2.friendly_id != novel1.friendly_id
94
+ end
95
+ end
96
+
84
97
  end
@@ -137,4 +137,63 @@ class SequentiallySluggedTestWithHistory < TestCaseClass
137
137
  assert_equal 'test-name-2', record2.slug
138
138
  end
139
139
  end
140
+
141
+ test "should work with regeneration with history when 2 slugs already exists and the second is changed" do
142
+ transaction do
143
+ record1 = model_class.create! :name => "Test name"
144
+ record2 = model_class.create! :name => "Test name"
145
+ record3 = model_class.create! :name => "Another test name"
146
+ assert_equal 'test-name', record1.slug
147
+ assert_equal 'test-name-2', record2.slug
148
+ assert_equal 'another-test-name', record3.slug
149
+
150
+ record2.name = "One more test name"
151
+ record2.slug = nil
152
+ record2.save!
153
+ assert_equal 'one-more-test-name', record2.slug
154
+
155
+ record3.name = "Test name"
156
+ record3.slug = nil
157
+ record3.save!
158
+ assert_equal 'test-name-3', record3.slug
159
+ end
160
+ end
161
+ end
162
+
163
+ class City < ActiveRecord::Base
164
+ has_many :restaurants
165
+ end
166
+
167
+ class Restaurant < ActiveRecord::Base
168
+ extend FriendlyId
169
+ belongs_to :city
170
+ friendly_id :name, :use => [:sequentially_slugged, :scoped, :history], :scope => :city
171
+ end
172
+
173
+ class SequentiallySluggedTestWithScopedHistory < TestCaseClass
174
+ include FriendlyId::Test
175
+ include FriendlyId::Test::Shared::Core
176
+
177
+ def model_class
178
+ Restaurant
179
+ end
180
+
181
+ test "should work with regeneration with scoped history" do
182
+ transaction do
183
+ city1 = City.create!
184
+ city2 = City.create!
185
+ record1 = model_class.create! :name => "Test name", :city => city1
186
+ record2 = model_class.create! :name => "Test name", :city => city1
187
+
188
+ assert_equal 'test-name', record1.slug
189
+ assert_equal 'test-name-2', record2.slug
190
+
191
+ record2.name = 'Another test name'
192
+ record2.slug = nil
193
+ record2.save!
194
+
195
+ record3 = model_class.create! :name => "Test name", :city => city1
196
+ assert_equal 'test-name-3', record3.slug
197
+ end
198
+ end
140
199
  end
@@ -62,7 +62,7 @@ module FriendlyId
62
62
  my_model_class = Class.new(model_class)
63
63
  self.class.const_set("Foo", my_model_class)
64
64
  with_instance_of my_model_class do |record|
65
- record.update_attributes my_model_class.friendly_id_config.slug_column => nil
65
+ record.update my_model_class.friendly_id_config.slug_column => nil
66
66
  record = my_model_class.friendly.find(record.id)
67
67
  record.class.validate Proc.new {errors.add(:name, "FAIL")}
68
68
  record.save
@@ -132,7 +132,7 @@ module FriendlyId
132
132
  test "updating record's other values should not change the friendly_id" do
133
133
  with_instance_of model_class do |record|
134
134
  old = record.friendly_id
135
- record.update_attributes! :active => false
135
+ record.update! active: false
136
136
  assert model_class.friendly.find old
137
137
  end
138
138
  end
@@ -91,14 +91,14 @@ class SimpleI18nTest < TestCaseClass
91
91
  class RegressionTest < TestCaseClass
92
92
  include FriendlyId::Test
93
93
 
94
- test "should not overwrite other locale's slugs on update_attributes" do
94
+ test "should not overwrite other locale's slugs on update" do
95
95
  transaction do
96
96
  journalist = Journalist.create!(:name => "John Smith")
97
97
  journalist.set_friendly_id("Juan Fulano", :es)
98
98
  journalist.save!
99
99
  assert_equal "john-smith", journalist.to_param
100
100
  journalist.slug = nil
101
- journalist.update_attributes :name => "Johnny Smith"
101
+ journalist.update :name => "Johnny Smith"
102
102
  assert_equal "johnny-smith", journalist.to_param
103
103
  I18n.with_locale(:es) do
104
104
  assert_equal "juan-fulano", journalist.to_param
@@ -92,7 +92,7 @@ class SluggedTest < TestCaseClass
92
92
  end
93
93
  end
94
94
 
95
- test "should not set slug on create if unrelated validations fail" do
95
+ test "should set slug on create if unrelated validations fail" do
96
96
  klass = Class.new model_class do
97
97
  validates_presence_of :active
98
98
  friendly_id :name, :use => :slugged
@@ -106,11 +106,30 @@ class SluggedTest < TestCaseClass
106
106
  instance = klass.new :name => 'foo'
107
107
  refute instance.save
108
108
  refute instance.valid?
109
+ assert_equal 'foo', instance.slug
110
+ end
111
+ end
112
+
113
+ test "should not set slug on create if slug validation fails" do
114
+ klass = Class.new model_class do
115
+ validates_presence_of :active
116
+ validates_length_of :slug, :minimum => 2
117
+ friendly_id :name, :use => :slugged
118
+
119
+ def self.name
120
+ "Journalist"
121
+ end
122
+ end
123
+
124
+ transaction do
125
+ instance = klass.new :name => 'x'
126
+ refute instance.save
127
+ refute instance.valid?
109
128
  assert_nil instance.slug
110
129
  end
111
130
  end
112
131
 
113
- test "should not set slug on create if unrelated validations fail with custom slug_column" do
132
+ test "should set slug on create if unrelated validations fail with custom slug_column" do
114
133
  klass = Class.new(ActiveRecord::Base) do
115
134
  self.table_name = 'authors'
116
135
  extend FriendlyId
@@ -126,11 +145,31 @@ class SluggedTest < TestCaseClass
126
145
  instance = klass.new :name => 'foo'
127
146
  refute instance.save
128
147
  refute instance.valid?
148
+ assert_equal 'foo', instance.subdomain
149
+ end
150
+ end
151
+
152
+ test "should not set slug on create if custom slug column validations fail" do
153
+ klass = Class.new(ActiveRecord::Base) do
154
+ self.table_name = 'authors'
155
+ extend FriendlyId
156
+ validates_length_of :subdomain, :minimum => 2
157
+ friendly_id :name, :use => :slugged, :slug_column => :subdomain
158
+
159
+ def self.name
160
+ "Author"
161
+ end
162
+ end
163
+
164
+ transaction do
165
+ instance = klass.new :name => 'x'
166
+ refute instance.save
167
+ refute instance.valid?
129
168
  assert_nil instance.subdomain
130
169
  end
131
170
  end
132
171
 
133
- test "should not update slug on save if unrelated validations fail" do
172
+ test "should keep new slug on save if unrelated validations fail" do
134
173
  klass = Class.new model_class do
135
174
  validates_presence_of :active
136
175
  friendly_id :name, :use => :slugged
@@ -149,10 +188,31 @@ class SluggedTest < TestCaseClass
149
188
  instance.active = nil
150
189
  refute instance.save
151
190
  refute instance.valid?
152
- assert_equal 'foo', instance.slug
191
+ assert_equal 'foobar', instance.slug
153
192
  end
154
193
  end
155
194
 
195
+ test "should not update slug on save if slug validations fail" do
196
+ klass = Class.new model_class do
197
+ validates_length_of :slug, :minimum => 2
198
+ friendly_id :name, :use => :slugged
199
+
200
+ def self.name
201
+ "Journalist"
202
+ end
203
+ end
204
+
205
+ transaction do
206
+ instance = klass.new :name => 'foo', :active => true
207
+ assert instance.save
208
+ assert instance.valid?
209
+ instance.name = 'x'
210
+ instance.slug = nil
211
+ instance.active = nil
212
+ refute instance.save
213
+ assert_equal 'foo', instance.slug
214
+ end
215
+ end
156
216
  end
157
217
 
158
218
  class SlugGeneratorTest < TestCaseClass
@@ -419,6 +479,110 @@ class FailedValidationAfterUpdateRegressionTest < TestCaseClass
419
479
 
420
480
  end
421
481
 
482
+ class ToParamTest < TestCaseClass
483
+
484
+ include FriendlyId::Test
485
+
486
+ class Journalist < ActiveRecord::Base
487
+ extend FriendlyId
488
+ validates_presence_of :active
489
+ validates_length_of :slug, :minimum => 2
490
+ friendly_id :name, :use => :slugged
491
+
492
+ attr_accessor :to_param_in_callback
493
+
494
+ after_save do
495
+ self.to_param_in_callback = to_param
496
+ end
497
+ end
498
+
499
+ test "to_param should return nil if record is unpersisted" do
500
+ assert_nil Journalist.new.to_param
501
+ end
502
+
503
+ test "to_param should return original slug if record failed validation" do
504
+ journalist = Journalist.new :name => 'Clark Kent', :active => nil
505
+ refute journalist.save
506
+ assert_equal 'clark-kent', journalist.to_param
507
+ end
508
+
509
+ test "to_param should clear slug attributes if slug attribute fails validation" do
510
+ journalist = Journalist.new :name => 'x', :active => true
511
+ refute journalist.save
512
+ assert_nil journalist.to_param
513
+ end
514
+
515
+ test "to_param should clear slug attribute if slug attribute fails validation and unrelated validation fails" do
516
+ journalist = Journalist.new :name => 'x', :active => nil
517
+ refute journalist.save
518
+ assert_nil journalist.to_param
519
+ end
520
+
521
+ test "to_param should use slugged attribute if record saved successfully" do
522
+ transaction do
523
+ journalist = Journalist.new :name => 'Clark Kent', :active => true
524
+ assert journalist.save
525
+ assert_equal 'clark-kent', journalist.to_param
526
+ end
527
+ end
528
+
529
+ test "to_param should use new slug if existing record changes but fails to save" do
530
+ transaction do
531
+ journalist = Journalist.new :name => 'Clark Kent', :active => true
532
+ assert journalist.save
533
+ journalist.name = 'Superman'
534
+ journalist.slug = nil
535
+ journalist.active = nil
536
+ refute journalist.save
537
+ assert_equal 'superman', journalist.to_param
538
+ end
539
+ end
540
+
541
+ test "to_param should use original slug if new slug attribute is not valid" do
542
+ transaction do
543
+ journalist = Journalist.new :name => 'Clark Kent', :active => true
544
+ assert journalist.save
545
+ journalist.name = 'x'
546
+ journalist.slug = nil
547
+ journalist.active = nil
548
+ refute journalist.save
549
+ assert_equal 'clark-kent', journalist.to_param
550
+ end
551
+ end
552
+
553
+ test "to_param should use new slug if existing record changes successfully" do
554
+ transaction do
555
+ journalist = Journalist.new :name => 'Clark Kent', :active => true
556
+ assert journalist.save
557
+ journalist.name = 'Superman'
558
+ journalist.slug = nil
559
+ assert journalist.save
560
+ assert_equal 'superman', journalist.to_param
561
+ end
562
+ end
563
+
564
+ test "to_param should use new slug within callbacks if new record is saved successfully" do
565
+ transaction do
566
+ journalist = Journalist.new :name => 'Clark Kent', :active => true
567
+ assert journalist.save
568
+ assert_equal 'clark-kent', journalist.to_param_in_callback, "value of to_param in callback should use the new slug value"
569
+ end
570
+ end
571
+
572
+ test "to_param should use new slug within callbacks if existing record changes successfully" do
573
+ transaction do
574
+ journalist = Journalist.new :name => 'Clark Kent', :active => true
575
+ assert journalist.save
576
+ assert journalist.valid?
577
+ journalist.name = 'Superman'
578
+ journalist.slug = nil
579
+ assert journalist.save, "save should be successful"
580
+ assert_equal 'superman', journalist.to_param_in_callback, "value of to_param in callback should use the new slug value"
581
+ end
582
+ end
583
+
584
+ end
585
+
422
586
  class ConfigurableRoutesTest < TestCaseClass
423
587
  include FriendlyId::Test
424
588
 
metadata CHANGED
@@ -1,15 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.3
4
+ version: 5.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Norman Clarke
8
8
  - Philip Arndt
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
- cert_chain: []
12
- date: 2017-09-21 00:00:00.000000000 Z
11
+ cert_chain:
12
+ - |
13
+ -----BEGIN CERTIFICATE-----
14
+ MIIEMjCCApqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhnZW1z
15
+ L0RDPXAvREM9YXJuZHQvREM9aW8wHhcNMjAwNTEwMjIxOTQ2WhcNMjEwNTEwMjIx
16
+ OTQ2WjAjMSEwHwYDVQQDDBhnZW1zL0RDPXAvREM9YXJuZHQvREM9aW8wggGiMA0G
17
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDT+JzHYPGMYJt9ct2DCsbIymn1uJJp
18
+ HnDkQESfsGe40jTC90oF2iVbVOkaacNc1N3CSWUZvZjuygUuS86P6/kpBILGdO2+
19
+ bkXXKtfGC2YGGx9TdNLpCb4925vQHvdFeKXGpQDZdDw1SNC6zraZou47CvOE1cl2
20
+ Bp+1QMZuGRZ4+5CzOEWDWurjqce3O1jUEbyBB7z5H0h/YEaxfXipxhL1Dhi0sgkH
21
+ qP/e6SxzifdifdZCksJFQ06a1ji9hJY6eM23qbv/aaluVHAZSVBAQBS7rYniLo+N
22
+ G4vpFhoubQO5u8UluUtCaPUpI/qOvVcSaZn3ZkzlMwC8b1RwAeXBQmtFE2wnrv2i
23
+ ovTwoN7rHchwhgaHbkuFh4Wr92wGbrWL7J+X8rWKk1f8RF4kvtNE/NA6YrkxTpVh
24
+ QMyDmekt7rTxvcq2NneLGroWIUVCx/JID+Jw492LKQ6Sl1/P2TRzdEDtqZAZL0gt
25
+ xlWeMUfGG2D/gLnhs5qnaFaWQwGTmBnTgHcCAwEAAaNxMG8wCQYDVR0TBAIwADAL
26
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFEqtAyQVxPgKsrgoTQ1YmaIu/fmvMBoGA1Ud
27
+ EQQTMBGBD2dlbXNAcC5hcm5kdC5pbzAaBgNVHRIEEzARgQ9nZW1zQHAuYXJuZHQu
28
+ aW8wDQYJKoZIhvcNAQELBQADggGBALu2HM50B8xqlAXkCwavJDvWWtV9pG1igFUg
29
+ friZRWprUQ5nTaNmAd8p8qbJQwaIK2gt+DfYWfB9LtKnQTfbhLRBbmJ7zYw8LjKY
30
+ PwCs4RWjDAiuyCO3ppfsz+1bsMUXPLgWlaUkXsUy3nr2NruEFTO9zu3wGYQQ93Tt
31
+ vYSHOnP35UB4QjsjNrOO7FBaQfy6O909PP+GnVcJ62s9c26voJz63RSolwY7Jydw
32
+ XUlG68jjJKSoDHRzVTmNB7sX8rs8P2kvYkpIUXPHyls3mWBWjBWbdEYWESZrxI2x
33
+ dS7jY3AnfqhvsWra2pSREb2IDqPnJrHVOejnEI/zuuufUxLwDx3AC6SMdsyWkZ7V
34
+ 9OmLt2rg75Sct6h2220lO5ySqYtqAXuOMBDGv5L0zLalx1g8LACA7uILTKVWh8B8
35
+ Hsej0MQ3drCB1eA4c9OXdCUQJnY2aLTq3uNvTbZvoTgWK55eq3KLBJ4zzoKZ4tBX
36
+ /HIFI/fEwYlI1Ji3oikUrHkc4rWgaQ==
37
+ -----END CERTIFICATE-----
38
+ date: 2020-11-06 00:00:00.000000000 Z
13
39
  dependencies:
14
40
  - !ruby/object:Gem::Dependency
15
41
  name: activerecord
@@ -43,14 +69,14 @@ dependencies:
43
69
  name: railties
44
70
  requirement: !ruby/object:Gem::Requirement
45
71
  requirements:
46
- - - "~>"
72
+ - - ">="
47
73
  - !ruby/object:Gem::Version
48
74
  version: '4.0'
49
75
  type: :development
50
76
  prerelease: false
51
77
  version_requirements: !ruby/object:Gem::Requirement
52
78
  requirements:
53
- - - "~>"
79
+ - - ">="
54
80
  - !ruby/object:Gem::Version
55
81
  version: '4.0'
56
82
  - !ruby/object:Gem::Dependency
@@ -149,8 +175,10 @@ extensions: []
149
175
  extra_rdoc_files: []
150
176
  files:
151
177
  - ".gemtest"
178
+ - ".github/FUNDING.yml"
179
+ - ".github/stale.yml"
180
+ - ".github/workflows/test.yml"
152
181
  - ".gitignore"
153
- - ".travis.yml"
154
182
  - ".yardopts"
155
183
  - CONTRIBUTING.md
156
184
  - Changelog.md
@@ -158,12 +186,12 @@ files:
158
186
  - MIT-LICENSE
159
187
  - README.md
160
188
  - Rakefile
189
+ - UPGRADING.md
161
190
  - bench.rb
191
+ - certs/parndt.pem
162
192
  - friendly_id.gemspec
163
- - gemfiles/Gemfile.rails-4.0.rb
164
- - gemfiles/Gemfile.rails-4.1.rb
165
- - gemfiles/Gemfile.rails-4.2.rb
166
- - gemfiles/Gemfile.rails-5.0.rb
193
+ - gemfiles/Gemfile.rails-5.2.rb
194
+ - gemfiles/Gemfile.rails-6.0.rb
167
195
  - guide.rb
168
196
  - lib/friendly_id.rb
169
197
  - lib/friendly_id/.gitattributes
@@ -196,6 +224,7 @@ files:
196
224
  - test/generator_test.rb
197
225
  - test/helper.rb
198
226
  - test/history_test.rb
227
+ - test/numeric_slug_test.rb
199
228
  - test/object_utils_test.rb
200
229
  - test/reserved_test.rb
201
230
  - test/schema.rb
@@ -209,7 +238,7 @@ homepage: https://github.com/norman/friendly_id
209
238
  licenses:
210
239
  - MIT
211
240
  metadata: {}
212
- post_install_message:
241
+ post_install_message:
213
242
  rdoc_options: []
214
243
  require_paths:
215
244
  - lib
@@ -217,16 +246,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
217
246
  requirements:
218
247
  - - ">="
219
248
  - !ruby/object:Gem::Version
220
- version: 1.9.3
249
+ version: 2.1.0
221
250
  required_rubygems_version: !ruby/object:Gem::Requirement
222
251
  requirements:
223
252
  - - ">="
224
253
  - !ruby/object:Gem::Version
225
254
  version: '0'
226
255
  requirements: []
227
- rubyforge_project: friendly_id
228
- rubygems_version: 2.6.13
229
- signing_key:
256
+ rubygems_version: 3.1.4
257
+ signing_key:
230
258
  specification_version: 4
231
259
  summary: A comprehensive slugging and pretty-URL plugin.
232
260
  test_files: []