active_record_doctor 1.9.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +83 -19
- data/lib/active_record_doctor/config/default.rb +17 -0
- data/lib/active_record_doctor/detectors/base.rb +216 -56
- data/lib/active_record_doctor/detectors/extraneous_indexes.rb +38 -56
- data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +2 -6
- data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +88 -15
- data/lib/active_record_doctor/detectors/incorrect_length_validation.rb +60 -0
- data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +16 -9
- data/lib/active_record_doctor/detectors/missing_foreign_keys.rb +2 -4
- data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +14 -11
- data/lib/active_record_doctor/detectors/missing_presence_validation.rb +16 -10
- data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +61 -17
- data/lib/active_record_doctor/detectors/short_primary_key_type.rb +6 -2
- data/lib/active_record_doctor/detectors/undefined_table_references.rb +2 -4
- data/lib/active_record_doctor/detectors/unindexed_deleted_at.rb +6 -15
- data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +2 -4
- data/lib/active_record_doctor/logger/dummy.rb +11 -0
- data/lib/active_record_doctor/logger/hierarchical.rb +22 -0
- data/lib/active_record_doctor/logger.rb +6 -0
- data/lib/active_record_doctor/rake/task.rb +10 -1
- data/lib/active_record_doctor/runner.rb +8 -3
- data/lib/active_record_doctor/version.rb +1 -1
- data/lib/active_record_doctor.rb +4 -0
- data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +5 -5
- data/test/active_record_doctor/detectors/disable_test.rb +30 -0
- data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +34 -0
- data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +7 -7
- data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +220 -43
- data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +107 -0
- data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +35 -1
- data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +78 -21
- data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +89 -25
- data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +179 -15
- data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +27 -19
- data/test/active_record_doctor/detectors/undefined_table_references_test.rb +11 -13
- data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +9 -3
- data/test/active_record_doctor/runner_test.rb +18 -19
- data/test/setup.rb +15 -7
- metadata +25 -5
- data/test/model_factory.rb +0 -128
@@ -3,30 +3,30 @@
|
|
3
3
|
class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Test
|
4
4
|
def test_invoking_no_callbacks_suggests_delete_all
|
5
5
|
create_table(:companies) do
|
6
|
-
end.
|
6
|
+
end.define_model do
|
7
7
|
has_many :users, dependent: :destroy
|
8
8
|
end
|
9
9
|
|
10
10
|
create_table(:users) do |t|
|
11
11
|
t.references :companies
|
12
|
-
end.
|
12
|
+
end.define_model do
|
13
13
|
belongs_to :company
|
14
14
|
end
|
15
15
|
|
16
16
|
assert_problems(<<~OUTPUT)
|
17
|
-
use `dependent: :delete_all` or similar on
|
17
|
+
use `dependent: :delete_all` or similar on TransientRecord::Models::Company.users - associated model TransientRecord::Models::User has no callbacks and can be deleted in bulk
|
18
18
|
OUTPUT
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_invoking_callbacks_does_not_suggest_delete_all
|
22
22
|
create_table(:companies) do
|
23
|
-
end.
|
23
|
+
end.define_model do
|
24
24
|
has_many :users, dependent: :destroy
|
25
25
|
end
|
26
26
|
|
27
27
|
create_table(:users) do |t|
|
28
28
|
t.references :companies
|
29
|
-
end.
|
29
|
+
end.define_model do
|
30
30
|
belongs_to :company
|
31
31
|
|
32
32
|
before_destroy :log
|
@@ -40,13 +40,13 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
40
40
|
|
41
41
|
def test_skipping_callbacks_suggests_destroy
|
42
42
|
create_table(:companies) do
|
43
|
-
end.
|
43
|
+
end.define_model do
|
44
44
|
has_many :users, dependent: :delete_all
|
45
45
|
end
|
46
46
|
|
47
47
|
create_table(:users) do |t|
|
48
48
|
t.references :companies
|
49
|
-
end.
|
49
|
+
end.define_model do
|
50
50
|
belongs_to :company
|
51
51
|
|
52
52
|
before_destroy :log
|
@@ -56,19 +56,19 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
56
56
|
end
|
57
57
|
|
58
58
|
assert_problems(<<~OUTPUT)
|
59
|
-
use `dependent: :destroy` or similar on
|
59
|
+
use `dependent: :destroy` or similar on TransientRecord::Models::Company.users - associated model TransientRecord::Models::User has callbacks that are currently skipped
|
60
60
|
OUTPUT
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_invoking_callbacks_does_not_suggest_destroy
|
64
64
|
create_table(:companies) do
|
65
|
-
end.
|
65
|
+
end.define_model do
|
66
66
|
has_many :users, dependent: :destroy
|
67
67
|
end
|
68
68
|
|
69
69
|
create_table(:users) do |t|
|
70
70
|
t.references :companies
|
71
|
-
end.
|
71
|
+
end.define_model do
|
72
72
|
belongs_to :company
|
73
73
|
|
74
74
|
before_destroy :log
|
@@ -82,102 +82,102 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
82
82
|
|
83
83
|
def test_works_on_has_one
|
84
84
|
create_table(:companies) do
|
85
|
-
end.
|
86
|
-
has_one :owner, class_name: "
|
85
|
+
end.define_model do
|
86
|
+
has_one :owner, class_name: "TransientRecord::Models::User", dependent: :destroy
|
87
87
|
end
|
88
88
|
|
89
89
|
create_table(:users) do |t|
|
90
90
|
t.references :companies
|
91
|
-
end.
|
91
|
+
end.define_model do
|
92
92
|
belongs_to :company
|
93
93
|
end
|
94
94
|
|
95
95
|
assert_problems(<<~OUTPUT)
|
96
|
-
use `dependent: :delete` or similar on
|
96
|
+
use `dependent: :delete` or similar on TransientRecord::Models::Company.owner - associated model TransientRecord::Models::User has no callbacks and can be deleted without loading
|
97
97
|
OUTPUT
|
98
98
|
end
|
99
99
|
|
100
100
|
def test_works_on_belongs_to
|
101
101
|
create_table(:companies) do
|
102
|
-
end.
|
102
|
+
end.define_model do
|
103
103
|
has_many :users
|
104
104
|
end
|
105
105
|
|
106
106
|
create_table(:users) do |t|
|
107
107
|
t.references :company
|
108
|
-
end.
|
108
|
+
end.define_model do
|
109
109
|
belongs_to :company, dependent: :destroy
|
110
110
|
end
|
111
111
|
|
112
112
|
assert_problems(<<~OUTPUT)
|
113
|
-
use `dependent: :delete` or similar on
|
113
|
+
use `dependent: :delete` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has no callbacks and can be deleted without loading
|
114
114
|
OUTPUT
|
115
115
|
end
|
116
116
|
|
117
117
|
def test_no_foreign_key_on_second_level_association
|
118
118
|
create_table(:companies) do
|
119
|
-
end.
|
119
|
+
end.define_model do
|
120
120
|
has_many :users
|
121
121
|
has_many :projects
|
122
122
|
end
|
123
123
|
|
124
124
|
create_table(:users) do |t|
|
125
125
|
t.references :company
|
126
|
-
end.
|
126
|
+
end.define_model do
|
127
127
|
belongs_to :company, dependent: :destroy
|
128
128
|
end
|
129
129
|
|
130
130
|
create_table(:projects) do |t|
|
131
131
|
t.references :company
|
132
|
-
end.
|
132
|
+
end.define_model do
|
133
133
|
belongs_to :company
|
134
134
|
end
|
135
135
|
|
136
136
|
assert_problems(<<~OUTPUT)
|
137
|
-
use `dependent: :delete` or similar on
|
137
|
+
use `dependent: :delete` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has no callbacks and can be deleted without loading
|
138
138
|
OUTPUT
|
139
139
|
end
|
140
140
|
|
141
141
|
def test_nullify_foreign_key_on_second_level_association
|
142
142
|
create_table(:companies) do
|
143
|
-
end.
|
143
|
+
end.define_model do
|
144
144
|
has_many :users
|
145
145
|
has_many :projects
|
146
146
|
end
|
147
147
|
|
148
148
|
create_table(:users) do |t|
|
149
149
|
t.references :company
|
150
|
-
end.
|
150
|
+
end.define_model do
|
151
151
|
belongs_to :company, dependent: :destroy
|
152
152
|
end
|
153
153
|
|
154
154
|
create_table(:projects) do |t|
|
155
155
|
t.references :company, foreign_key: { on_delete: :nullify }
|
156
|
-
end.
|
156
|
+
end.define_model do
|
157
157
|
belongs_to :company
|
158
158
|
end
|
159
159
|
|
160
160
|
assert_problems(<<~OUTPUT)
|
161
|
-
use `dependent: :delete` or similar on
|
161
|
+
use `dependent: :delete` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has no callbacks and can be deleted without loading
|
162
162
|
OUTPUT
|
163
163
|
end
|
164
164
|
|
165
165
|
def test_cascade_foreign_key_and_callbacks_on_second_level_association
|
166
166
|
create_table(:companies) do
|
167
|
-
end.
|
167
|
+
end.define_model do
|
168
168
|
has_many :users
|
169
169
|
has_many :projects
|
170
170
|
end
|
171
171
|
|
172
172
|
create_table(:users) do |t|
|
173
173
|
t.references :company
|
174
|
-
end.
|
174
|
+
end.define_model do
|
175
175
|
belongs_to :company, dependent: :delete
|
176
176
|
end
|
177
177
|
|
178
178
|
create_table(:projects) do |t|
|
179
179
|
t.references :company, foreign_key: { on_delete: :cascade }
|
180
|
-
end.
|
180
|
+
end.define_model do
|
181
181
|
belongs_to :company
|
182
182
|
|
183
183
|
before_destroy :log
|
@@ -187,26 +187,26 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
187
187
|
end
|
188
188
|
|
189
189
|
assert_problems(<<~OUTPUT)
|
190
|
-
use `dependent: :destroy` or similar on
|
190
|
+
use `dependent: :destroy` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has callbacks that are currently skipped
|
191
191
|
OUTPUT
|
192
192
|
end
|
193
193
|
|
194
194
|
def test_cascade_foreign_key_and_no_callbacks_on_second_level_association
|
195
195
|
create_table(:companies) do
|
196
|
-
end.
|
196
|
+
end.define_model do
|
197
197
|
has_many :users
|
198
198
|
has_many :projects
|
199
199
|
end
|
200
200
|
|
201
201
|
create_table(:users) do |t|
|
202
202
|
t.references :company
|
203
|
-
end.
|
203
|
+
end.define_model do
|
204
204
|
belongs_to :company, dependent: :delete
|
205
205
|
end
|
206
206
|
|
207
207
|
create_table(:projects) do |t|
|
208
208
|
t.references :company, foreign_key: { on_delete: :cascade }
|
209
|
-
end.
|
209
|
+
end.define_model do
|
210
210
|
belongs_to :company
|
211
211
|
end
|
212
212
|
|
@@ -215,35 +215,212 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
215
215
|
|
216
216
|
def test_no_dependent_suggests_nothing
|
217
217
|
create_table(:companies) do
|
218
|
-
end.
|
218
|
+
end.define_model do
|
219
219
|
has_many :users
|
220
220
|
end
|
221
221
|
|
222
222
|
create_table(:users) do |t|
|
223
223
|
t.references :companies
|
224
|
-
end.
|
224
|
+
end.define_model do
|
225
225
|
belongs_to :company
|
226
226
|
end
|
227
227
|
|
228
228
|
refute_problems
|
229
229
|
end
|
230
230
|
|
231
|
+
def test_polymorphic_destroy_reported_when_all_associations_deletable
|
232
|
+
create_table(:images) do |t|
|
233
|
+
t.bigint :imageable_id, null: false
|
234
|
+
t.string :imageable_type, null: true
|
235
|
+
end.define_model do
|
236
|
+
belongs_to :imageable, polymorphic: true, dependent: :destroy
|
237
|
+
end
|
238
|
+
|
239
|
+
create_table(:users) do
|
240
|
+
end.define_model do
|
241
|
+
has_one :image, as: :imageable
|
242
|
+
end
|
243
|
+
|
244
|
+
create_table(:companies) do
|
245
|
+
end.define_model do
|
246
|
+
has_one :image, as: :imageable
|
247
|
+
end
|
248
|
+
|
249
|
+
assert_problems(<<~OUTPUT)
|
250
|
+
use `dependent: :delete` or similar on TransientRecord::Models::Image.imageable - associated models TransientRecord::Models::Company, TransientRecord::Models::User have no callbacks and can be deleted without loading
|
251
|
+
OUTPUT
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_polymorphic_destroy_not_reported_when_some_associations_not_deletable
|
255
|
+
create_table(:images) do |t|
|
256
|
+
t.bigint :imageable_id, null: false
|
257
|
+
t.string :imageable_type, null: true
|
258
|
+
end.define_model do
|
259
|
+
belongs_to :imageable, polymorphic: true, dependent: :destroy
|
260
|
+
end
|
261
|
+
|
262
|
+
create_table(:users) do
|
263
|
+
end.define_model do
|
264
|
+
has_one :image, as: :imageable
|
265
|
+
|
266
|
+
before_destroy :log
|
267
|
+
|
268
|
+
def log
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
create_table(:companies) do
|
273
|
+
end.define_model do
|
274
|
+
has_one :image, as: :imageable
|
275
|
+
end
|
276
|
+
|
277
|
+
refute_problems
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_polymorphic_delete_reported_when_some_associations_not_deletable
|
281
|
+
create_table(:images) do |t|
|
282
|
+
t.bigint :imageable_id, null: false
|
283
|
+
t.string :imageable_type, null: true
|
284
|
+
end.define_model do
|
285
|
+
belongs_to :imageable, polymorphic: true, dependent: :delete
|
286
|
+
end
|
287
|
+
|
288
|
+
create_table(:users) do
|
289
|
+
end.define_model do
|
290
|
+
has_one :image, as: :imageable
|
291
|
+
|
292
|
+
before_destroy :log
|
293
|
+
|
294
|
+
def log
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
create_table(:companies) do
|
299
|
+
end.define_model do
|
300
|
+
has_one :image, as: :imageable
|
301
|
+
end
|
302
|
+
|
303
|
+
assert_problems(<<~OUTPUT)
|
304
|
+
use `dependent: :destroy` or similar on TransientRecord::Models::Image.imageable - associated model TransientRecord::Models::User has callbacks that are currently skipped
|
305
|
+
OUTPUT
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_polymorphic_delete_not_reported_when_all_associations_deletable
|
309
|
+
create_table(:images) do |t|
|
310
|
+
t.bigint :imageable_id, null: false
|
311
|
+
t.string :imageable_type, null: true
|
312
|
+
end.define_model do
|
313
|
+
belongs_to :imageable, polymorphic: true, dependent: :delete
|
314
|
+
end
|
315
|
+
|
316
|
+
create_table(:users) do
|
317
|
+
end.define_model do
|
318
|
+
has_one :image, as: :imageable
|
319
|
+
end
|
320
|
+
|
321
|
+
create_table(:companies) do
|
322
|
+
end.define_model do
|
323
|
+
has_one :image, as: :imageable
|
324
|
+
end
|
325
|
+
|
326
|
+
refute_problems
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_works_on_has_through_associations_with_destroy
|
330
|
+
create_table(:users) do
|
331
|
+
end.define_model do
|
332
|
+
has_many :posts
|
333
|
+
has_many :comments, through: :posts, dependent: :destroy
|
334
|
+
end
|
335
|
+
|
336
|
+
create_table(:posts) do |t|
|
337
|
+
t.references :users
|
338
|
+
end.define_model do
|
339
|
+
belongs_to :user
|
340
|
+
has_many :comments
|
341
|
+
end
|
342
|
+
|
343
|
+
create_table(:comments) do |t|
|
344
|
+
t.references :posts
|
345
|
+
end.define_model do
|
346
|
+
belongs_to :post
|
347
|
+
end
|
348
|
+
|
349
|
+
assert_problems(<<~OUTPUT)
|
350
|
+
use `dependent: :delete_all` or similar on TransientRecord::Models::User.comments - associated join model TransientRecord::Models::Post has no callbacks and can be deleted in bulk
|
351
|
+
OUTPUT
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_works_on_has_through_associations_with_delete_all
|
355
|
+
create_table(:users) do
|
356
|
+
end.define_model do
|
357
|
+
has_many :posts
|
358
|
+
has_many :comments, through: :posts, dependent: :delete_all
|
359
|
+
end
|
360
|
+
|
361
|
+
create_table(:posts) do |t|
|
362
|
+
t.references :users
|
363
|
+
end.define_model do
|
364
|
+
belongs_to :user
|
365
|
+
has_many :comments
|
366
|
+
|
367
|
+
before_destroy :log
|
368
|
+
|
369
|
+
def log
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
create_table(:comments) do |t|
|
374
|
+
t.references :posts
|
375
|
+
end.define_model do
|
376
|
+
belongs_to :post
|
377
|
+
end
|
378
|
+
|
379
|
+
assert_problems(<<~OUTPUT)
|
380
|
+
use `dependent: :destroy` or similar on TransientRecord::Models::User.comments - associated join model TransientRecord::Models::Post has callbacks that are currently skipped
|
381
|
+
OUTPUT
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_has_through_associations_when_join_model_incomplete
|
385
|
+
create_table(:users) do
|
386
|
+
end.define_model do
|
387
|
+
has_many :posts
|
388
|
+
has_many :comments, through: :posts
|
389
|
+
end
|
390
|
+
|
391
|
+
create_table(:posts) do |t|
|
392
|
+
t.references :users
|
393
|
+
end.define_model do
|
394
|
+
# The join model should define has_many :comments, but intentionally skips
|
395
|
+
# it for this test case's purpose.
|
396
|
+
end
|
397
|
+
|
398
|
+
create_table(:comments) do |t|
|
399
|
+
t.references :posts
|
400
|
+
end.define_model do
|
401
|
+
end
|
402
|
+
|
403
|
+
assert_problems(<<~OUTPUT)
|
404
|
+
ensure TransientRecord::Models::User.comments is configured correctly - TransientRecord::Models::Post.comments may be undefined
|
405
|
+
OUTPUT
|
406
|
+
end
|
407
|
+
|
231
408
|
def test_config_ignore_models
|
232
409
|
create_table(:companies) do
|
233
|
-
end.
|
410
|
+
end.define_model do
|
234
411
|
has_many :users, dependent: :destroy
|
235
412
|
end
|
236
413
|
|
237
414
|
create_table(:users) do |t|
|
238
415
|
t.references :companies
|
239
|
-
end.
|
416
|
+
end.define_model do
|
240
417
|
belongs_to :company
|
241
418
|
end
|
242
419
|
|
243
420
|
config_file(<<-CONFIG)
|
244
421
|
ActiveRecordDoctor.configure do |config|
|
245
422
|
config.detector :incorrect_dependent_option,
|
246
|
-
ignore_models: ["
|
423
|
+
ignore_models: ["TransientRecord::Models::Company"]
|
247
424
|
end
|
248
425
|
CONFIG
|
249
426
|
|
@@ -252,19 +429,19 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
252
429
|
|
253
430
|
def test_global_ignore_models
|
254
431
|
create_table(:companies) do
|
255
|
-
end.
|
432
|
+
end.define_model do
|
256
433
|
has_many :users, dependent: :destroy
|
257
434
|
end
|
258
435
|
|
259
436
|
create_table(:users) do |t|
|
260
437
|
t.references :companies
|
261
|
-
end.
|
438
|
+
end.define_model do
|
262
439
|
belongs_to :company
|
263
440
|
end
|
264
441
|
|
265
442
|
config_file(<<-CONFIG)
|
266
443
|
ActiveRecordDoctor.configure do |config|
|
267
|
-
config.global :ignore_models, ["
|
444
|
+
config.global :ignore_models, ["TransientRecord::Models::Company"]
|
268
445
|
end
|
269
446
|
CONFIG
|
270
447
|
|
@@ -273,20 +450,20 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
273
450
|
|
274
451
|
def test_config_ignore_associations
|
275
452
|
create_table(:companies) do
|
276
|
-
end.
|
453
|
+
end.define_model do
|
277
454
|
has_many :users, dependent: :destroy
|
278
455
|
end
|
279
456
|
|
280
457
|
create_table(:users) do |t|
|
281
458
|
t.references :companies
|
282
|
-
end.
|
459
|
+
end.define_model do
|
283
460
|
belongs_to :company
|
284
461
|
end
|
285
462
|
|
286
463
|
config_file(<<-CONFIG)
|
287
464
|
ActiveRecordDoctor.configure do |config|
|
288
465
|
config.detector :incorrect_dependent_option,
|
289
|
-
ignore_associations: ["
|
466
|
+
ignore_associations: ["TransientRecord::Models::Company.users"]
|
290
467
|
end
|
291
468
|
CONFIG
|
292
469
|
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActiveRecordDoctor::Detectors::IncorrectLengthValidationTest < Minitest::Test
|
4
|
+
def test_validation_and_limit_equal_is_ok
|
5
|
+
create_table(:users) do |t|
|
6
|
+
t.string :email, limit: 64
|
7
|
+
t.string :name, limit: 32
|
8
|
+
end.define_model do
|
9
|
+
validates :email, length: { maximum: 64 }
|
10
|
+
validates :name, length: { maximum: 32 }
|
11
|
+
end
|
12
|
+
|
13
|
+
refute_problems
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_validation_and_limit_different_is_error
|
17
|
+
create_table(:users) do |t|
|
18
|
+
t.string :email, limit: 64
|
19
|
+
end.define_model do
|
20
|
+
validates :email, length: { maximum: 32 }
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_problems(<<~OUTPUT)
|
24
|
+
the schema limits users.email to 64 characters but the length validator on TransientRecord::Models::User.email enforces a maximum of 32 characters - set both limits to the same value or remove both
|
25
|
+
OUTPUT
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_validation_and_no_limit_is_error
|
29
|
+
skip("MySQL always sets a limit on text columns") if mysql?
|
30
|
+
|
31
|
+
create_table(:users) do |t|
|
32
|
+
t.string :email
|
33
|
+
end.define_model do
|
34
|
+
validates :email, length: { maximum: 32 }
|
35
|
+
end
|
36
|
+
|
37
|
+
assert_problems(<<~OUTPUT)
|
38
|
+
the length validator on TransientRecord::Models::User.email enforces a maximum of 32 characters but there's no schema limit on users.email - remove the validator or the schema length limit
|
39
|
+
OUTPUT
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_no_validation_and_limit_is_error
|
43
|
+
create_table(:users) do |t|
|
44
|
+
t.string :email, limit: 64
|
45
|
+
end.define_model do
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_problems(<<~OUTPUT)
|
49
|
+
the schema limits users.email to 64 characters but there's no length validator on TransientRecord::Models::User.email - remove the database limit or add the validator
|
50
|
+
OUTPUT
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_no_validation_and_no_limit_is_ok
|
54
|
+
skip("MySQL always sets a limit on text columns") if mysql?
|
55
|
+
|
56
|
+
create_table(:users) do |t|
|
57
|
+
t.string :email
|
58
|
+
end.define_model do
|
59
|
+
end
|
60
|
+
|
61
|
+
refute_problems
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_config_ignore_models
|
65
|
+
create_table(:users) do |t|
|
66
|
+
t.string :email, limit: 64
|
67
|
+
end.define_model
|
68
|
+
|
69
|
+
config_file(<<-CONFIG)
|
70
|
+
ActiveRecordDoctor.configure do |config|
|
71
|
+
config.detector :incorrect_length_validation,
|
72
|
+
ignore_models: ["TransientRecord::Models::User"]
|
73
|
+
end
|
74
|
+
CONFIG
|
75
|
+
|
76
|
+
refute_problems
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_global_ignore_models
|
80
|
+
create_table(:users) do |t|
|
81
|
+
t.string :email, limit: 64
|
82
|
+
end.define_model
|
83
|
+
|
84
|
+
config_file(<<-CONFIG)
|
85
|
+
ActiveRecordDoctor.configure do |config|
|
86
|
+
config.global :ignore_models, ["TransientRecord::Models::User"]
|
87
|
+
end
|
88
|
+
CONFIG
|
89
|
+
|
90
|
+
refute_problems
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_config_ignore_attributes
|
94
|
+
create_table(:users) do |t|
|
95
|
+
t.string :email, limit: 64
|
96
|
+
end.define_model
|
97
|
+
|
98
|
+
config_file(<<-CONFIG)
|
99
|
+
ActiveRecordDoctor.configure do |config|
|
100
|
+
config.detector :incorrect_length_validation,
|
101
|
+
ignore_attributes: ["TransientRecord::Models::User.email"]
|
102
|
+
end
|
103
|
+
CONFIG
|
104
|
+
|
105
|
+
refute_problems
|
106
|
+
end
|
107
|
+
end
|
@@ -11,7 +11,7 @@ class ActiveRecordDoctor::Detectors::MismatchedForeignKeyTypeTest < Minitest::Te
|
|
11
11
|
end
|
12
12
|
|
13
13
|
assert_problems(<<~OUTPUT)
|
14
|
-
users.company_id
|
14
|
+
users.company_id is a foreign key of type integer and references companies.id of type bigint - foreign keys should be of the same type as the referenced column
|
15
15
|
OUTPUT
|
16
16
|
end
|
17
17
|
|
@@ -24,6 +24,40 @@ class ActiveRecordDoctor::Detectors::MismatchedForeignKeyTypeTest < Minitest::Te
|
|
24
24
|
refute_problems
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_mismatched_foreign_key_with_non_primary_key_type_is_reported
|
28
|
+
# MySQL does not allow foreign keys to have different type than paired primary keys
|
29
|
+
return if mysql?
|
30
|
+
|
31
|
+
create_table(:companies, id: :bigint) do |t|
|
32
|
+
t.string :code
|
33
|
+
t.index :code, unique: true
|
34
|
+
end
|
35
|
+
create_table(:users) do |t|
|
36
|
+
t.text :code
|
37
|
+
t.foreign_key :companies, table: :companies, column: :code, primary_key: :code
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_problems(<<~OUTPUT)
|
41
|
+
users.code is a foreign key of type text and references companies.code of type character varying - foreign keys should be of the same type as the referenced column
|
42
|
+
OUTPUT
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_matched_foreign_key_with_non_primary_key_type_is_not_reported
|
46
|
+
# MySQL does not allow foreign keys to have different type than paired primary keys
|
47
|
+
return if mysql?
|
48
|
+
|
49
|
+
create_table(:companies, id: :bigint) do |t|
|
50
|
+
t.string :code
|
51
|
+
t.index :code, unique: true
|
52
|
+
end
|
53
|
+
create_table(:users) do |t|
|
54
|
+
t.string :code
|
55
|
+
t.foreign_key :companies, table: :companies, column: :code, primary_key: :code
|
56
|
+
end
|
57
|
+
|
58
|
+
refute_problems
|
59
|
+
end
|
60
|
+
|
27
61
|
def test_config_ignore_tables
|
28
62
|
# MySQL does not allow foreign keys to have different type than paired primary keys
|
29
63
|
return if mysql?
|