friendly_id 5.6.0 → 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.
@@ -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
@@ -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
data/test/scoped_test.rb DELETED
@@ -1,95 +0,0 @@
1
- require "helper"
2
-
3
- class Novelist < ActiveRecord::Base
4
- extend FriendlyId
5
- friendly_id :name, use: :slugged
6
- end
7
-
8
- class Novel < ActiveRecord::Base
9
- extend FriendlyId
10
- belongs_to :novelist
11
- belongs_to :publisher
12
- friendly_id :name, use: :scoped, scope: [:publisher, :novelist]
13
-
14
- def should_generate_new_friendly_id?
15
- new_record? || super
16
- end
17
- end
18
-
19
- class Publisher < ActiveRecord::Base
20
- has_many :novels
21
- end
22
-
23
- class ScopedTest < TestCaseClass
24
- include FriendlyId::Test
25
- include FriendlyId::Test::Shared::Core
26
-
27
- def model_class
28
- Novel
29
- end
30
-
31
- test "should detect scope column from belongs_to relation" do
32
- assert_equal ["publisher_id", "novelist_id"], Novel.friendly_id_config.scope_columns
33
- end
34
-
35
- test "should detect scope column from explicit column name" do
36
- model_class = Class.new(ActiveRecord::Base) do
37
- self.abstract_class = true
38
- extend FriendlyId
39
- friendly_id :empty, use: :scoped, scope: :dummy
40
- end
41
- assert_equal ["dummy"], model_class.friendly_id_config.scope_columns
42
- end
43
-
44
- test "should allow duplicate slugs outside scope" do
45
- transaction do
46
- novel1 = Novel.create! name: "a", novelist: Novelist.create!(name: "a")
47
- novel2 = Novel.create! name: "a", novelist: Novelist.create!(name: "b")
48
- assert_equal novel1.friendly_id, novel2.friendly_id
49
- end
50
- end
51
-
52
- test "should not allow duplicate slugs inside scope" do
53
- with_instance_of Novelist do |novelist|
54
- novel1 = Novel.create! name: "a", novelist: novelist
55
- novel2 = Novel.create! name: "a", novelist: novelist
56
- assert novel1.friendly_id != novel2.friendly_id
57
- end
58
- end
59
-
60
- test "should apply scope with multiple columns" do
61
- transaction do
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
68
- assert_equal novel1.friendly_id, novel2.friendly_id
69
- assert_equal novel2.friendly_id, novel3.friendly_id
70
- assert novel3.friendly_id != novel4.friendly_id
71
- end
72
- end
73
-
74
- test "should allow a record to reuse its own slug" do
75
- with_instance_of(model_class) do |record|
76
- old_id = record.friendly_id
77
- record.slug = nil
78
- record.save!
79
- assert_equal old_id, record.friendly_id
80
- end
81
- end
82
-
83
- test "should generate new slug when scope changes" do
84
- transaction do
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")
89
- assert_equal novel1.friendly_id, novel2.friendly_id
90
- novel2.publisher = publisher
91
- novel2.save!
92
- assert novel2.friendly_id != novel1.friendly_id
93
- end
94
- end
95
- end
@@ -1,214 +0,0 @@
1
- require "helper"
2
-
3
- class Article < ActiveRecord::Base
4
- extend FriendlyId
5
- friendly_id :name, use: :sequentially_slugged
6
- end
7
-
8
- class SequentiallySluggedTest < TestCaseClass
9
- include FriendlyId::Test
10
- include FriendlyId::Test::Shared::Core
11
-
12
- def model_class
13
- Article
14
- end
15
-
16
- test "should generate numerically sequential slugs" do
17
- transaction do
18
- records = 12.times.map { model_class.create! name: "Some news" }
19
- assert_equal "some-news", records[0].slug
20
- (1...12).each { |i| assert_equal "some-news-#{i + 1}", records[i].slug }
21
- end
22
- end
23
-
24
- test "should cope when slugs are missing from the sequence" do
25
- transaction do
26
- record_1 = model_class.create!(name: "A thing")
27
- record_2 = model_class.create!(name: "A thing")
28
- record_3 = model_class.create!(name: "A thing")
29
-
30
- assert_equal "a-thing", record_1.slug
31
- assert_equal "a-thing-2", record_2.slug
32
- assert_equal "a-thing-3", record_3.slug
33
-
34
- record_2.destroy
35
-
36
- record_4 = model_class.create!(name: "A thing")
37
-
38
- assert_equal "a-thing-4", record_4.slug
39
- end
40
- end
41
-
42
- test "should cope with strange column names" do
43
- model_class = Class.new(ActiveRecord::Base) do
44
- self.table_name = "journalists"
45
- extend FriendlyId
46
- friendly_id :name, use: :sequentially_slugged, slug_column: "strange name"
47
- end
48
-
49
- transaction do
50
- record_1 = model_class.create! name: "Lois Lane"
51
- record_2 = model_class.create! name: "Lois Lane"
52
-
53
- assert_equal "lois-lane", record_1.attributes["strange name"]
54
- assert_equal "lois-lane-2", record_2.attributes["strange name"]
55
- end
56
- end
57
-
58
- test "should correctly sequence slugs that end in a number" do
59
- transaction do
60
- record1 = model_class.create! name: "Peugeuot 206"
61
- assert_equal "peugeuot-206", record1.slug
62
- record2 = model_class.create! name: "Peugeuot 206"
63
- assert_equal "peugeuot-206-2", record2.slug
64
- end
65
- end
66
-
67
- test "should correctly sequence slugs that begin with a number" do
68
- transaction do
69
- record1 = model_class.create! name: "2010 to 2015 Records"
70
- assert_equal "2010-to-2015-records", record1.slug
71
- record2 = model_class.create! name: "2010 to 2015 Records"
72
- assert_equal "2010-to-2015-records-2", record2.slug
73
- end
74
- end
75
-
76
- test "should sequence with a custom sequence separator" do
77
- model_class = Class.new(ActiveRecord::Base) do
78
- self.table_name = "novelists"
79
- extend FriendlyId
80
- friendly_id :name, use: :sequentially_slugged, sequence_separator: ":"
81
- end
82
-
83
- transaction do
84
- record_1 = model_class.create! name: "Julian Barnes"
85
- record_2 = model_class.create! name: "Julian Barnes"
86
-
87
- assert_equal "julian-barnes", record_1.slug
88
- assert_equal "julian-barnes:2", record_2.slug
89
- end
90
- end
91
-
92
- test "should not generate a slug when canidates set is empty" do
93
- model_class = Class.new(ActiveRecord::Base) do
94
- self.table_name = "cities"
95
- extend FriendlyId
96
- friendly_id :slug_candidates, use: [:sequentially_slugged]
97
-
98
- def slug_candidates
99
- [name, [name, code]]
100
- end
101
- end
102
- transaction do
103
- record = model_class.create!(name: nil, code: nil)
104
- assert_nil record.slug
105
- end
106
- end
107
-
108
- test "should not generate a slug when the sluggable attribute is blank" do
109
- record = model_class.create!(name: "")
110
- assert_nil record.slug
111
- end
112
- end
113
-
114
- class SequentiallySluggedTestWithHistory < TestCaseClass
115
- include FriendlyId::Test
116
- include FriendlyId::Test::Shared::Core
117
-
118
- class Article < ActiveRecord::Base
119
- extend FriendlyId
120
- friendly_id :name, use: [:sequentially_slugged, :history]
121
- end
122
-
123
- Journalist = Class.new(ActiveRecord::Base) do
124
- extend FriendlyId
125
- friendly_id :name, use: [:sequentially_slugged, :history], slug_column: "strange name"
126
- end
127
-
128
- def model_class
129
- Article
130
- end
131
-
132
- test "should work with regeneration with history when slug already exists" do
133
- transaction do
134
- record1 = model_class.create! name: "Test name"
135
- record2 = model_class.create! name: "Another test name"
136
- assert_equal "test-name", record1.slug
137
- assert_equal "another-test-name", record2.slug
138
-
139
- record2.name = "Test name"
140
- record2.slug = nil
141
- record2.save!
142
- assert_equal "test-name-2", record2.slug
143
- end
144
- end
145
-
146
- test "should work with regeneration with history when 2 slugs already exists and the second is changed" do
147
- transaction do
148
- record1 = model_class.create! name: "Test name"
149
- record2 = model_class.create! name: "Test name"
150
- record3 = model_class.create! name: "Another test name"
151
- assert_equal "test-name", record1.slug
152
- assert_equal "test-name-2", record2.slug
153
- assert_equal "another-test-name", record3.slug
154
-
155
- record2.name = "One more test name"
156
- record2.slug = nil
157
- record2.save!
158
- assert_equal "one-more-test-name", record2.slug
159
-
160
- record3.name = "Test name"
161
- record3.slug = nil
162
- record3.save!
163
- assert_equal "test-name-3", record3.slug
164
- end
165
- end
166
-
167
- test "should cope with strange column names" do
168
- transaction do
169
- record_1 = Journalist.create! name: "Lois Lane"
170
- record_2 = Journalist.create! name: "Lois Lane"
171
-
172
- assert_equal "lois-lane", record_1.attributes["strange name"]
173
- assert_equal "lois-lane-2", record_2.attributes["strange name"]
174
- end
175
- end
176
- end
177
-
178
- class City < ActiveRecord::Base
179
- has_many :restaurants
180
- end
181
-
182
- class Restaurant < ActiveRecord::Base
183
- extend FriendlyId
184
- belongs_to :city
185
- friendly_id :name, use: [:sequentially_slugged, :scoped, :history], scope: :city
186
- end
187
-
188
- class SequentiallySluggedTestWithScopedHistory < TestCaseClass
189
- include FriendlyId::Test
190
- include FriendlyId::Test::Shared::Core
191
-
192
- def model_class
193
- Restaurant
194
- end
195
-
196
- test "should work with regeneration with scoped history" do
197
- transaction do
198
- city1 = City.create!
199
- City.create!
200
- record1 = model_class.create! name: "Test name", city: city1
201
- record2 = model_class.create! name: "Test name", city: city1
202
-
203
- assert_equal "test-name", record1.slug
204
- assert_equal "test-name-2", record2.slug
205
-
206
- record2.name = "Another test name"
207
- record2.slug = nil
208
- record2.save!
209
-
210
- record3 = model_class.create! name: "Test name", city: city1
211
- assert_equal "test-name-3", record3.slug
212
- end
213
- end
214
- end
data/test/shared.rb DELETED
@@ -1,181 +0,0 @@
1
- module FriendlyId
2
- module Test
3
- module Shared
4
- module Slugged
5
- test "configuration should have a sequence_separator" do
6
- assert !model_class.friendly_id_config.sequence_separator.empty?
7
- end
8
-
9
- test "should make a new slug if the slug has been set to nil changed" do
10
- with_instance_of model_class do |record|
11
- record.name = "Changed Value"
12
- record.slug = nil
13
- record.save!
14
- assert_equal "changed-value", record.slug
15
- end
16
- end
17
-
18
- test "should add a UUID for duplicate friendly ids" do
19
- with_instance_of model_class do |record|
20
- record2 = model_class.create! name: record.name
21
- assert record2.friendly_id.match(/([0-9a-z]+-){4}[0-9a-z]+\z/)
22
- end
23
- end
24
-
25
- test "should not add slug sequence on update after other conflicting slugs were added" do
26
- with_instance_of model_class do |record|
27
- old = record.friendly_id
28
- model_class.create! name: record.name
29
- record.save!
30
- record.reload
31
- assert_equal old, record.to_param
32
- end
33
- end
34
-
35
- test "should not change the sequence on save" do
36
- with_instance_of model_class do |record|
37
- record2 = model_class.create! name: record.name
38
- friendly_id = record2.friendly_id
39
- record2.active = !record2.active
40
- record2.save!
41
- assert_equal friendly_id, record2.reload.friendly_id
42
- end
43
- end
44
-
45
- test "should create slug on save if the slug is nil" do
46
- with_instance_of model_class do |record|
47
- record.slug = nil
48
- record.save!
49
- refute_nil record.slug
50
- end
51
- end
52
-
53
- test "should set the slug to nil on dup" do
54
- with_instance_of model_class do |record|
55
- record2 = record.dup
56
- assert_nil record2.slug
57
- end
58
- end
59
-
60
- test "when validations block save, to_param should return friendly_id rather than nil" do
61
- my_model_class = Class.new(model_class)
62
- self.class.const_set("Foo", my_model_class)
63
- with_instance_of my_model_class do |record|
64
- record.update my_model_class.friendly_id_config.slug_column => nil
65
- record = my_model_class.friendly.find(record.id)
66
- record.class.validate proc { errors.add(:name, "FAIL") }
67
- record.save
68
- assert_equal record.to_param, record.friendly_id
69
- end
70
- end
71
- end
72
-
73
- module Core
74
- test "finds should respect conditions" do
75
- with_instance_of(model_class) do |record|
76
- assert_raises(ActiveRecord::RecordNotFound) do
77
- model_class.where("1 = 2").friendly.find record.friendly_id
78
- end
79
- assert_raises(ActiveRecord::RecordNotFound) do
80
- model_class.where("1 = 2").friendly.find record.id
81
- end
82
- end
83
- end
84
-
85
- test "should be findable by friendly id" do
86
- with_instance_of(model_class) { |record| assert model_class.friendly.find record.friendly_id }
87
- end
88
-
89
- test "should exist? by friendly id" do
90
- with_instance_of(model_class) do |record|
91
- assert model_class.friendly.exists? record.id
92
- assert model_class.friendly.exists? record.id.to_s
93
- assert model_class.friendly.exists? record.friendly_id
94
- assert model_class.friendly.exists?({id: record.id})
95
- assert model_class.friendly.exists?(["id = ?", record.id])
96
- assert !model_class.friendly.exists?(record.friendly_id + "-hello")
97
- assert !model_class.friendly.exists?(0)
98
- end
99
- end
100
-
101
- test "should be findable by id as integer" do
102
- with_instance_of(model_class) { |record| assert model_class.friendly.find record.id.to_i }
103
- end
104
-
105
- test "should be findable by id as string" do
106
- with_instance_of(model_class) { |record| assert model_class.friendly.find record.id.to_s }
107
- end
108
-
109
- test "should treat numeric part of string as an integer id" do
110
- with_instance_of(model_class) do |record|
111
- assert_raises(ActiveRecord::RecordNotFound) do
112
- model_class.friendly.find "#{record.id}-foo"
113
- end
114
- end
115
- end
116
-
117
- test "should be findable by numeric friendly_id" do
118
- with_instance_of(model_class, name: "206") { |record| assert model_class.friendly.find record.friendly_id }
119
- end
120
-
121
- test "to_param should return the friendly_id" do
122
- with_instance_of(model_class) { |record| assert_equal record.friendly_id, record.to_param }
123
- end
124
-
125
- if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR < 2
126
- test "should be findable by themselves" do
127
- with_instance_of(model_class) { |record| assert_equal record, model_class.friendly.find(record) }
128
- end
129
- end
130
-
131
- test "updating record's other values should not change the friendly_id" do
132
- with_instance_of model_class do |record|
133
- old = record.friendly_id
134
- record.update! active: false
135
- assert model_class.friendly.find old
136
- end
137
- end
138
-
139
- test "instances found by a single id should not be read-only" do
140
- with_instance_of(model_class) { |record| assert !model_class.friendly.find(record.friendly_id).readonly? }
141
- end
142
-
143
- test "failing finds with unfriendly_id should raise errors normally" do
144
- assert_raises(ActiveRecord::RecordNotFound) { model_class.friendly.find 0 }
145
- end
146
-
147
- test "should return numeric id if the friendly_id is nil" do
148
- with_instance_of(model_class) do |record|
149
- record.expects(:friendly_id).returns(nil)
150
- assert_equal record.id.to_s, record.to_param
151
- end
152
- end
153
-
154
- test "should return numeric id if the friendly_id is an empty string" do
155
- with_instance_of(model_class) do |record|
156
- record.expects(:friendly_id).returns("")
157
- assert_equal record.id.to_s, record.to_param
158
- end
159
- end
160
-
161
- test "should return the friendly_id as a string" do
162
- with_instance_of(model_class) do |record|
163
- record.expects(:friendly_id).returns(5)
164
- assert_equal "5", record.to_param
165
- end
166
- end
167
-
168
- test "should return numeric id if the friendly_id is blank" do
169
- with_instance_of(model_class) do |record|
170
- record.expects(:friendly_id).returns(" ")
171
- assert_equal record.id.to_s, record.to_param
172
- end
173
- end
174
-
175
- test "should return nil for to_param with a new record" do
176
- assert_nil model_class.new.to_param
177
- end
178
- end
179
- end
180
- end
181
- end