active_record_doctor 1.8.0 → 1.10.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 +316 -54
- data/lib/active_record_doctor/config/default.rb +76 -0
- data/lib/active_record_doctor/config/loader.rb +137 -0
- data/lib/active_record_doctor/config.rb +14 -0
- data/lib/active_record_doctor/detectors/base.rb +142 -21
- data/lib/active_record_doctor/detectors/extraneous_indexes.rb +59 -48
- data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +31 -23
- data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +102 -35
- data/lib/active_record_doctor/detectors/incorrect_length_validation.rb +63 -0
- data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +45 -0
- data/lib/active_record_doctor/detectors/missing_foreign_keys.rb +32 -23
- data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +41 -28
- data/lib/active_record_doctor/detectors/missing_presence_validation.rb +29 -23
- data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +92 -32
- data/lib/active_record_doctor/detectors/short_primary_key_type.rb +45 -0
- data/lib/active_record_doctor/detectors/undefined_table_references.rb +17 -20
- data/lib/active_record_doctor/detectors/unindexed_deleted_at.rb +43 -18
- data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +31 -20
- data/lib/active_record_doctor/detectors.rb +12 -4
- data/lib/active_record_doctor/errors.rb +226 -0
- data/lib/active_record_doctor/help.rb +39 -0
- data/lib/active_record_doctor/rake/task.rb +78 -0
- data/lib/active_record_doctor/runner.rb +41 -0
- data/lib/active_record_doctor/version.rb +1 -1
- data/lib/active_record_doctor.rb +8 -3
- data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +34 -21
- data/lib/tasks/active_record_doctor.rake +9 -18
- data/test/active_record_doctor/config/loader_test.rb +120 -0
- data/test/active_record_doctor/config_test.rb +116 -0
- data/test/active_record_doctor/detectors/disable_test.rb +30 -0
- data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +165 -8
- data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +48 -5
- data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +288 -12
- data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +105 -0
- data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +82 -0
- data/test/active_record_doctor/detectors/missing_foreign_keys_test.rb +50 -4
- data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +172 -24
- data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +111 -14
- data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +223 -10
- data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +72 -0
- data/test/active_record_doctor/detectors/undefined_table_references_test.rb +34 -21
- data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +118 -8
- data/test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb +56 -4
- data/test/active_record_doctor/runner_test.rb +42 -0
- data/test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb +131 -0
- data/test/model_factory.rb +73 -23
- data/test/setup.rb +65 -71
- metadata +43 -7
- data/lib/active_record_doctor/printers/io_printer.rb +0 -133
- data/lib/active_record_doctor/task.rb +0 -28
- data/test/active_record_doctor/printers/io_printer_test.rb +0 -33
@@ -13,10 +13,9 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
|
|
13
13
|
belongs_to :company
|
14
14
|
end
|
15
15
|
|
16
|
-
assert_problems(
|
17
|
-
|
18
|
-
|
19
|
-
OUTPUT
|
16
|
+
assert_problems(<<~OUTPUT)
|
17
|
+
use `dependent: :delete_all` or similar on ModelFactory::Models::Company.users - associated model ModelFactory::Models::User has no validations and can be deleted in bulk
|
18
|
+
OUTPUT
|
20
19
|
end
|
21
20
|
|
22
21
|
def test_invoking_callbacks_does_not_suggest_delete_all
|
@@ -56,10 +55,9 @@ OUTPUT
|
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
59
|
-
assert_problems(
|
60
|
-
|
61
|
-
|
62
|
-
OUTPUT
|
58
|
+
assert_problems(<<~OUTPUT)
|
59
|
+
use `dependent: :destroy` or similar on ModelFactory::Models::Company.users - the associated model ModelFactory::Models::User has callbacks that are currently skipped
|
60
|
+
OUTPUT
|
63
61
|
end
|
64
62
|
|
65
63
|
def test_invoking_callbacks_does_not_suggest_destroy
|
@@ -94,10 +92,125 @@ OUTPUT
|
|
94
92
|
belongs_to :company
|
95
93
|
end
|
96
94
|
|
97
|
-
assert_problems(
|
98
|
-
|
99
|
-
|
100
|
-
|
95
|
+
assert_problems(<<~OUTPUT)
|
96
|
+
use `dependent: :delete` or similar on ModelFactory::Models::Company.owner - the associated model ModelFactory::Models::User has no callbacks and can be deleted without loading
|
97
|
+
OUTPUT
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_works_on_belongs_to
|
101
|
+
create_table(:companies) do
|
102
|
+
end.create_model do
|
103
|
+
has_many :users
|
104
|
+
end
|
105
|
+
|
106
|
+
create_table(:users) do |t|
|
107
|
+
t.references :company
|
108
|
+
end.create_model do
|
109
|
+
belongs_to :company, dependent: :destroy
|
110
|
+
end
|
111
|
+
|
112
|
+
assert_problems(<<~OUTPUT)
|
113
|
+
use `dependent: :delete` or similar on ModelFactory::Models::User.company - the associated model ModelFactory::Models::Company has no callbacks and can be deleted without loading
|
114
|
+
OUTPUT
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_no_foreign_key_on_second_level_association
|
118
|
+
create_table(:companies) do
|
119
|
+
end.create_model do
|
120
|
+
has_many :users
|
121
|
+
has_many :projects
|
122
|
+
end
|
123
|
+
|
124
|
+
create_table(:users) do |t|
|
125
|
+
t.references :company
|
126
|
+
end.create_model do
|
127
|
+
belongs_to :company, dependent: :destroy
|
128
|
+
end
|
129
|
+
|
130
|
+
create_table(:projects) do |t|
|
131
|
+
t.references :company
|
132
|
+
end.create_model do
|
133
|
+
belongs_to :company
|
134
|
+
end
|
135
|
+
|
136
|
+
assert_problems(<<~OUTPUT)
|
137
|
+
use `dependent: :delete` or similar on ModelFactory::Models::User.company - the associated model ModelFactory::Models::Company has no callbacks and can be deleted without loading
|
138
|
+
OUTPUT
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_nullify_foreign_key_on_second_level_association
|
142
|
+
create_table(:companies) do
|
143
|
+
end.create_model do
|
144
|
+
has_many :users
|
145
|
+
has_many :projects
|
146
|
+
end
|
147
|
+
|
148
|
+
create_table(:users) do |t|
|
149
|
+
t.references :company
|
150
|
+
end.create_model do
|
151
|
+
belongs_to :company, dependent: :destroy
|
152
|
+
end
|
153
|
+
|
154
|
+
create_table(:projects) do |t|
|
155
|
+
t.references :company, foreign_key: { on_delete: :nullify }
|
156
|
+
end.create_model do
|
157
|
+
belongs_to :company
|
158
|
+
end
|
159
|
+
|
160
|
+
assert_problems(<<~OUTPUT)
|
161
|
+
use `dependent: :delete` or similar on ModelFactory::Models::User.company - the associated model ModelFactory::Models::Company has no callbacks and can be deleted without loading
|
162
|
+
OUTPUT
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_cascade_foreign_key_and_callbacks_on_second_level_association
|
166
|
+
create_table(:companies) do
|
167
|
+
end.create_model do
|
168
|
+
has_many :users
|
169
|
+
has_many :projects
|
170
|
+
end
|
171
|
+
|
172
|
+
create_table(:users) do |t|
|
173
|
+
t.references :company
|
174
|
+
end.create_model do
|
175
|
+
belongs_to :company, dependent: :delete
|
176
|
+
end
|
177
|
+
|
178
|
+
create_table(:projects) do |t|
|
179
|
+
t.references :company, foreign_key: { on_delete: :cascade }
|
180
|
+
end.create_model do
|
181
|
+
belongs_to :company
|
182
|
+
|
183
|
+
before_destroy :log
|
184
|
+
|
185
|
+
def log
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
assert_problems(<<~OUTPUT)
|
190
|
+
use `dependent: :destroy` or similar on ModelFactory::Models::User.company - the associated model ModelFactory::Models::Company has callbacks that are currently skipped
|
191
|
+
OUTPUT
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_cascade_foreign_key_and_no_callbacks_on_second_level_association
|
195
|
+
create_table(:companies) do
|
196
|
+
end.create_model do
|
197
|
+
has_many :users
|
198
|
+
has_many :projects
|
199
|
+
end
|
200
|
+
|
201
|
+
create_table(:users) do |t|
|
202
|
+
t.references :company
|
203
|
+
end.create_model do
|
204
|
+
belongs_to :company, dependent: :delete
|
205
|
+
end
|
206
|
+
|
207
|
+
create_table(:projects) do |t|
|
208
|
+
t.references :company, foreign_key: { on_delete: :cascade }
|
209
|
+
end.create_model do
|
210
|
+
belongs_to :company
|
211
|
+
end
|
212
|
+
|
213
|
+
refute_problems
|
101
214
|
end
|
102
215
|
|
103
216
|
def test_no_dependent_suggests_nothing
|
@@ -114,4 +227,167 @@ OUTPUT
|
|
114
227
|
|
115
228
|
refute_problems
|
116
229
|
end
|
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.create_model do
|
236
|
+
belongs_to :imageable, polymorphic: true, dependent: :destroy
|
237
|
+
end
|
238
|
+
|
239
|
+
create_table(:users) do
|
240
|
+
end.create_model do
|
241
|
+
has_one :image, as: :imageable
|
242
|
+
end
|
243
|
+
|
244
|
+
create_table(:companies) do
|
245
|
+
end.create_model do
|
246
|
+
has_one :image, as: :imageable
|
247
|
+
end
|
248
|
+
|
249
|
+
assert_problems(<<~OUTPUT)
|
250
|
+
use `dependent: :delete` or similar on ModelFactory::Models::Image.imageable - the associated models ModelFactory::Models::Company, ModelFactory::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.create_model do
|
259
|
+
belongs_to :imageable, polymorphic: true, dependent: :destroy
|
260
|
+
end
|
261
|
+
|
262
|
+
create_table(:users) do
|
263
|
+
end.create_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.create_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.create_model do
|
285
|
+
belongs_to :imageable, polymorphic: true, dependent: :delete
|
286
|
+
end
|
287
|
+
|
288
|
+
create_table(:users) do
|
289
|
+
end.create_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.create_model do
|
300
|
+
has_one :image, as: :imageable
|
301
|
+
end
|
302
|
+
|
303
|
+
assert_problems(<<~OUTPUT)
|
304
|
+
use `dependent: :destroy` or similar on ModelFactory::Models::Image.imageable - the associated model ModelFactory::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.create_model do
|
313
|
+
belongs_to :imageable, polymorphic: true, dependent: :delete
|
314
|
+
end
|
315
|
+
|
316
|
+
create_table(:users) do
|
317
|
+
end.create_model do
|
318
|
+
has_one :image, as: :imageable
|
319
|
+
end
|
320
|
+
|
321
|
+
create_table(:companies) do
|
322
|
+
end.create_model do
|
323
|
+
has_one :image, as: :imageable
|
324
|
+
end
|
325
|
+
|
326
|
+
refute_problems
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_config_ignore_models
|
330
|
+
create_table(:companies) do
|
331
|
+
end.create_model do
|
332
|
+
has_many :users, dependent: :destroy
|
333
|
+
end
|
334
|
+
|
335
|
+
create_table(:users) do |t|
|
336
|
+
t.references :companies
|
337
|
+
end.create_model do
|
338
|
+
belongs_to :company
|
339
|
+
end
|
340
|
+
|
341
|
+
config_file(<<-CONFIG)
|
342
|
+
ActiveRecordDoctor.configure do |config|
|
343
|
+
config.detector :incorrect_dependent_option,
|
344
|
+
ignore_models: ["ModelFactory::Models::Company"]
|
345
|
+
end
|
346
|
+
CONFIG
|
347
|
+
|
348
|
+
refute_problems
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_global_ignore_models
|
352
|
+
create_table(:companies) do
|
353
|
+
end.create_model do
|
354
|
+
has_many :users, dependent: :destroy
|
355
|
+
end
|
356
|
+
|
357
|
+
create_table(:users) do |t|
|
358
|
+
t.references :companies
|
359
|
+
end.create_model do
|
360
|
+
belongs_to :company
|
361
|
+
end
|
362
|
+
|
363
|
+
config_file(<<-CONFIG)
|
364
|
+
ActiveRecordDoctor.configure do |config|
|
365
|
+
config.global :ignore_models, ["ModelFactory::Models::Company"]
|
366
|
+
end
|
367
|
+
CONFIG
|
368
|
+
|
369
|
+
refute_problems
|
370
|
+
end
|
371
|
+
|
372
|
+
def test_config_ignore_associations
|
373
|
+
create_table(:companies) do
|
374
|
+
end.create_model do
|
375
|
+
has_many :users, dependent: :destroy
|
376
|
+
end
|
377
|
+
|
378
|
+
create_table(:users) do |t|
|
379
|
+
t.references :companies
|
380
|
+
end.create_model do
|
381
|
+
belongs_to :company
|
382
|
+
end
|
383
|
+
|
384
|
+
config_file(<<-CONFIG)
|
385
|
+
ActiveRecordDoctor.configure do |config|
|
386
|
+
config.detector :incorrect_dependent_option,
|
387
|
+
ignore_associations: ["ModelFactory::Models::Company.users"]
|
388
|
+
end
|
389
|
+
CONFIG
|
390
|
+
|
391
|
+
refute_problems
|
392
|
+
end
|
117
393
|
end
|
@@ -0,0 +1,105 @@
|
|
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
|
+
end.create_model do
|
8
|
+
validates :email, length: { maximum: 64 }
|
9
|
+
end
|
10
|
+
|
11
|
+
refute_problems
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_validation_and_limit_different_is_error
|
15
|
+
create_table(:users) do |t|
|
16
|
+
t.string :email, limit: 64
|
17
|
+
end.create_model do
|
18
|
+
validates :email, length: { maximum: 32 }
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_problems(<<~OUTPUT)
|
22
|
+
the schema limits users.email to 64 characters but the length validator on ModelFactory::Models::User.email enforces a maximum of 32 characters - set both limits to the same value or remove both
|
23
|
+
OUTPUT
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_validation_and_no_limit_is_error
|
27
|
+
skip("MySQL always sets a limit on text columns") if mysql?
|
28
|
+
|
29
|
+
create_table(:users) do |t|
|
30
|
+
t.string :email
|
31
|
+
end.create_model do
|
32
|
+
validates :email, length: { maximum: 32 }
|
33
|
+
end
|
34
|
+
|
35
|
+
assert_problems(<<~OUTPUT)
|
36
|
+
the length validator on ModelFactory::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
|
37
|
+
OUTPUT
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_no_validation_and_limit_is_error
|
41
|
+
create_table(:users) do |t|
|
42
|
+
t.string :email, limit: 64
|
43
|
+
end.create_model do
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_problems(<<~OUTPUT)
|
47
|
+
the schema limits users.email to 64 characters but there's no length validator on ModelFactory::Models::User.email - remove the database limit or add the validator
|
48
|
+
OUTPUT
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_no_validation_and_no_limit_is_ok
|
52
|
+
skip("MySQL always sets a limit on text columns") if mysql?
|
53
|
+
|
54
|
+
create_table(:users) do |t|
|
55
|
+
t.string :email
|
56
|
+
end.create_model do
|
57
|
+
end
|
58
|
+
|
59
|
+
refute_problems
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_config_ignore_models
|
63
|
+
create_table(:users) do |t|
|
64
|
+
t.string :email, limit: 64
|
65
|
+
end.create_model
|
66
|
+
|
67
|
+
config_file(<<-CONFIG)
|
68
|
+
ActiveRecordDoctor.configure do |config|
|
69
|
+
config.detector :incorrect_length_validation,
|
70
|
+
ignore_models: ["ModelFactory::Models::User"]
|
71
|
+
end
|
72
|
+
CONFIG
|
73
|
+
|
74
|
+
refute_problems
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_global_ignore_models
|
78
|
+
create_table(:users) do |t|
|
79
|
+
t.string :email, limit: 64
|
80
|
+
end.create_model
|
81
|
+
|
82
|
+
config_file(<<-CONFIG)
|
83
|
+
ActiveRecordDoctor.configure do |config|
|
84
|
+
config.global :ignore_models, ["ModelFactory::Models::User"]
|
85
|
+
end
|
86
|
+
CONFIG
|
87
|
+
|
88
|
+
refute_problems
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_config_ignore_attributes
|
92
|
+
create_table(:users) do |t|
|
93
|
+
t.string :email, limit: 64
|
94
|
+
end.create_model
|
95
|
+
|
96
|
+
config_file(<<-CONFIG)
|
97
|
+
ActiveRecordDoctor.configure do |config|
|
98
|
+
config.detector :incorrect_length_validation,
|
99
|
+
ignore_attributes: ["ModelFactory::Models::User.email"]
|
100
|
+
end
|
101
|
+
CONFIG
|
102
|
+
|
103
|
+
refute_problems
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActiveRecordDoctor::Detectors::MismatchedForeignKeyTypeTest < Minitest::Test
|
4
|
+
def test_mismatched_foreign_key_type_is_reported
|
5
|
+
# MySQL does not allow foreign keys to have different type than paired primary keys
|
6
|
+
return if mysql?
|
7
|
+
|
8
|
+
create_table(:companies, id: :bigint)
|
9
|
+
create_table(:users) do |t|
|
10
|
+
t.references :company, foreign_key: true, type: :integer
|
11
|
+
end
|
12
|
+
|
13
|
+
assert_problems(<<~OUTPUT)
|
14
|
+
users.company_id references a column of different type - foreign keys should be of the same type as the referenced column
|
15
|
+
OUTPUT
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_matched_foreign_key_type_is_not_reported
|
19
|
+
create_table(:companies)
|
20
|
+
create_table(:users) do |t|
|
21
|
+
t.references :company, foreign_key: true
|
22
|
+
end
|
23
|
+
|
24
|
+
refute_problems
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_config_ignore_tables
|
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)
|
32
|
+
create_table(:users) do |t|
|
33
|
+
t.references :company, foreign_key: true, type: :integer
|
34
|
+
end
|
35
|
+
|
36
|
+
config_file(<<-CONFIG)
|
37
|
+
ActiveRecordDoctor.configure do |config|
|
38
|
+
config.detector :mismatched_foreign_key_type,
|
39
|
+
ignore_tables: ["users"]
|
40
|
+
end
|
41
|
+
CONFIG
|
42
|
+
|
43
|
+
refute_problems
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_global_ignore_tables
|
47
|
+
# MySQL does not allow foreign keys to have different type than paired primary keys
|
48
|
+
return if mysql?
|
49
|
+
|
50
|
+
create_table(:companies, id: :bigint)
|
51
|
+
create_table(:users) do |t|
|
52
|
+
t.references :company, foreign_key: true, type: :integer
|
53
|
+
end
|
54
|
+
|
55
|
+
config_file(<<-CONFIG)
|
56
|
+
ActiveRecordDoctor.configure do |config|
|
57
|
+
config.global :ignore_tables, ["users"]
|
58
|
+
end
|
59
|
+
CONFIG
|
60
|
+
|
61
|
+
refute_problems
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_config_ignore_columns
|
65
|
+
# MySQL does not allow foreign keys to have different type than paired primary keys
|
66
|
+
return if mysql?
|
67
|
+
|
68
|
+
create_table(:companies, id: :bigint)
|
69
|
+
create_table(:users) do |t|
|
70
|
+
t.references :company, foreign_key: true, type: :integer
|
71
|
+
end
|
72
|
+
|
73
|
+
config_file(<<-CONFIG)
|
74
|
+
ActiveRecordDoctor.configure do |config|
|
75
|
+
config.detector :mismatched_foreign_key_type,
|
76
|
+
ignore_columns: ["users.company_id"]
|
77
|
+
end
|
78
|
+
CONFIG
|
79
|
+
|
80
|
+
refute_problems
|
81
|
+
end
|
82
|
+
end
|
@@ -7,10 +7,9 @@ class ActiveRecordDoctor::Detectors::MissingForeignKeysTest < Minitest::Test
|
|
7
7
|
t.references :company, foreign_key: false
|
8
8
|
end
|
9
9
|
|
10
|
-
assert_problems(
|
11
|
-
|
12
|
-
|
13
|
-
OUTPUT
|
10
|
+
assert_problems(<<~OUTPUT)
|
11
|
+
create a foreign key on users.company_id - looks like an association without a foreign key constraint
|
12
|
+
OUTPUT
|
14
13
|
end
|
15
14
|
|
16
15
|
def test_present_foreign_key_is_not_reported
|
@@ -21,4 +20,51 @@ OUTPUT
|
|
21
20
|
|
22
21
|
refute_problems
|
23
22
|
end
|
23
|
+
|
24
|
+
def test_config_ignore_models
|
25
|
+
create_table(:companies)
|
26
|
+
create_table(:users) do |t|
|
27
|
+
t.references :company, foreign_key: false
|
28
|
+
end
|
29
|
+
|
30
|
+
config_file(<<-CONFIG)
|
31
|
+
ActiveRecordDoctor.configure do |config|
|
32
|
+
config.detector :missing_foreign_keys,
|
33
|
+
ignore_tables: ["users"]
|
34
|
+
end
|
35
|
+
CONFIG
|
36
|
+
|
37
|
+
refute_problems
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_global_ignore_models
|
41
|
+
create_table(:companies)
|
42
|
+
create_table(:users) do |t|
|
43
|
+
t.references :company, foreign_key: false
|
44
|
+
end
|
45
|
+
|
46
|
+
config_file(<<-CONFIG)
|
47
|
+
ActiveRecordDoctor.configure do |config|
|
48
|
+
config.global :ignore_tables, ["users"]
|
49
|
+
end
|
50
|
+
CONFIG
|
51
|
+
|
52
|
+
refute_problems
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_config_ignore_columns
|
56
|
+
create_table(:companies)
|
57
|
+
create_table(:users) do |t|
|
58
|
+
t.references :company, foreign_key: false
|
59
|
+
end
|
60
|
+
|
61
|
+
config_file(<<-CONFIG)
|
62
|
+
ActiveRecordDoctor.configure do |config|
|
63
|
+
config.detector :missing_foreign_keys,
|
64
|
+
ignore_columns: ["users.company_id"]
|
65
|
+
end
|
66
|
+
CONFIG
|
67
|
+
|
68
|
+
refute_problems
|
69
|
+
end
|
24
70
|
end
|