active_record_doctor 1.10.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/active_record_doctor/detectors/base.rb +180 -50
- data/lib/active_record_doctor/detectors/extraneous_indexes.rb +24 -27
- data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +2 -5
- data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +63 -21
- data/lib/active_record_doctor/detectors/incorrect_length_validation.rb +7 -10
- 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 +13 -11
- data/lib/active_record_doctor/detectors/missing_presence_validation.rb +14 -7
- data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +5 -11
- data/lib/active_record_doctor/detectors/short_primary_key_type.rb +1 -1
- data/lib/active_record_doctor/detectors/undefined_table_references.rb +2 -2
- data/lib/active_record_doctor/detectors/unindexed_deleted_at.rb +5 -13
- 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 +3 -0
- data/test/active_record_doctor/detectors/disable_test.rb +1 -1
- 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 +136 -57
- data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +16 -14
- 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 +46 -23
- data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +55 -27
- data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +36 -36
- data/test/active_record_doctor/detectors/undefined_table_references_test.rb +11 -13
- data/test/active_record_doctor/runner_test.rb +18 -19
- data/test/setup.rb +10 -6
- metadata +19 -4
- data/test/model_factory.rb +0 -128
@@ -4,7 +4,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
4
4
|
def test_optional_columns_with_presence_validator_are_disallowed
|
5
5
|
create_table(:users) do |t|
|
6
6
|
t.string :name, null: true
|
7
|
-
end.
|
7
|
+
end.define_model do
|
8
8
|
validates :name, presence: true
|
9
9
|
end
|
10
10
|
|
@@ -17,7 +17,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
17
17
|
create_table(:companies)
|
18
18
|
create_table(:users) do |t|
|
19
19
|
t.references :company, null: true
|
20
|
-
end.
|
20
|
+
end.define_model do
|
21
21
|
belongs_to :company, required: true
|
22
22
|
end
|
23
23
|
|
@@ -26,10 +26,33 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
26
26
|
OUTPUT
|
27
27
|
end
|
28
28
|
|
29
|
+
def test_optional_columns_with_required_polymorphic_association_are_disallowed
|
30
|
+
create_table(:comments) do |t|
|
31
|
+
t.references :commentable, polymorphic: true, null: true
|
32
|
+
end.define_model do
|
33
|
+
belongs_to :commentable, polymorphic: true, required: true
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_problems(<<~OUTPUT)
|
37
|
+
add `NOT NULL` to comments.commentable_id - models validates its presence but it's not non-NULL in the database
|
38
|
+
add `NOT NULL` to comments.commentable_type - models validates its presence but it's not non-NULL in the database
|
39
|
+
OUTPUT
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_required_columns_with_required_polymorphic_association_are_allowed
|
43
|
+
create_table(:comments) do |t|
|
44
|
+
t.references :commentable, polymorphic: true, null: false
|
45
|
+
end.define_model do
|
46
|
+
belongs_to :commentable, polymorphic: true, required: true
|
47
|
+
end
|
48
|
+
|
49
|
+
refute_problems
|
50
|
+
end
|
51
|
+
|
29
52
|
def test_required_columns_with_presence_validators_are_allowed
|
30
53
|
create_table(:users) do |t|
|
31
54
|
t.string :name, null: false
|
32
|
-
end.
|
55
|
+
end.define_model do
|
33
56
|
validates :name, presence: true
|
34
57
|
end
|
35
58
|
|
@@ -39,7 +62,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
39
62
|
def test_optional_columns_without_presence_validator_are_allowed
|
40
63
|
create_table(:users) do |t|
|
41
64
|
t.string :name, null: false
|
42
|
-
end.
|
65
|
+
end.define_model do
|
43
66
|
validates :name, presence: false
|
44
67
|
end
|
45
68
|
|
@@ -49,7 +72,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
49
72
|
def test_validators_matched_to_correct_columns
|
50
73
|
create_table(:users) do |t|
|
51
74
|
t.string :name, null: true
|
52
|
-
end.
|
75
|
+
end.define_model do
|
53
76
|
# The age validator is a form of regression test against a bug that
|
54
77
|
# caused false positives. In this test case, name is NOT validated
|
55
78
|
# for presence so it does NOT need be marked non-NULL. However, the
|
@@ -65,7 +88,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
65
88
|
def test_validators_with_if_on_optional_columns_are_allowed
|
66
89
|
create_table(:users) do |t|
|
67
90
|
t.string :name, null: true
|
68
|
-
end.
|
91
|
+
end.define_model do
|
69
92
|
validates :name, presence: true, if: -> { false }
|
70
93
|
end
|
71
94
|
|
@@ -75,7 +98,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
75
98
|
def test_validators_with_unless_on_optional_columns_are_allowed
|
76
99
|
create_table(:users) do |t|
|
77
100
|
t.string :name, null: true
|
78
|
-
end.
|
101
|
+
end.define_model do
|
79
102
|
validates :name, presence: true, unless: -> { false }
|
80
103
|
end
|
81
104
|
|
@@ -85,7 +108,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
85
108
|
def test_validators_allowing_nil_on_optional_columns_are_allowed
|
86
109
|
create_table(:users) do |t|
|
87
110
|
t.string :name, null: true
|
88
|
-
end.
|
111
|
+
end.define_model do
|
89
112
|
validates :name, presence: true, allow_nil: true
|
90
113
|
end
|
91
114
|
|
@@ -93,7 +116,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
93
116
|
end
|
94
117
|
|
95
118
|
def test_models_with_non_existent_tables_are_skipped
|
96
|
-
|
119
|
+
define_model(:User)
|
97
120
|
|
98
121
|
refute_problems
|
99
122
|
end
|
@@ -102,9 +125,9 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
102
125
|
create_table(:users) do |t|
|
103
126
|
t.string :type, null: false
|
104
127
|
t.string :email, null: true
|
105
|
-
end.
|
128
|
+
end.define_model
|
106
129
|
|
107
|
-
|
130
|
+
define_model(:Client, TransientRecord::Models::User) do
|
108
131
|
validates :email, presence: true
|
109
132
|
end
|
110
133
|
|
@@ -117,13 +140,13 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
117
140
|
create_table(:users) do |t|
|
118
141
|
t.string :type, null: false
|
119
142
|
t.string :email, null: true
|
120
|
-
end.
|
143
|
+
end.define_model
|
121
144
|
|
122
|
-
|
145
|
+
define_model(:Client, TransientRecord::Models::User) do
|
123
146
|
validates :email, presence: true
|
124
147
|
end
|
125
148
|
|
126
|
-
|
149
|
+
define_model(:Admin, TransientRecord::Models::User) do
|
127
150
|
validates :email, presence: false
|
128
151
|
end
|
129
152
|
|
@@ -133,11 +156,11 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
133
156
|
def test_optional_columns_validated_by_all_non_sti_models_are_disallowed
|
134
157
|
create_table(:users) do |t|
|
135
158
|
t.string :email, null: true
|
136
|
-
end.
|
159
|
+
end.define_model do
|
137
160
|
validates :email, presence: true
|
138
161
|
end
|
139
162
|
|
140
|
-
|
163
|
+
define_model(:Client) do
|
141
164
|
self.table_name = :users
|
142
165
|
|
143
166
|
validates :email, presence: true
|
@@ -151,11 +174,11 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
151
174
|
def test_optional_columns_validated_by_some_non_sti_models_are_allowed
|
152
175
|
create_table(:users) do |t|
|
153
176
|
t.string :email, null: true
|
154
|
-
end.
|
177
|
+
end.define_model do
|
155
178
|
validates :email, presence: true
|
156
179
|
end
|
157
180
|
|
158
|
-
|
181
|
+
define_model(:Client) do
|
159
182
|
self.table_name = :users
|
160
183
|
|
161
184
|
validates :email, presence: false
|
@@ -169,7 +192,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
169
192
|
|
170
193
|
create_table(:users) do |t|
|
171
194
|
t.string :email
|
172
|
-
end.
|
195
|
+
end.define_model do
|
173
196
|
validates :email, presence: true
|
174
197
|
end
|
175
198
|
|
@@ -185,7 +208,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
185
208
|
|
186
209
|
create_table(:users) do |t|
|
187
210
|
t.string :email
|
188
|
-
end.
|
211
|
+
end.define_model do
|
189
212
|
validates :email, presence: true
|
190
213
|
end
|
191
214
|
|
@@ -201,7 +224,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
201
224
|
def test_config_ignore_tables
|
202
225
|
create_table(:users) do |t|
|
203
226
|
t.string :name, null: true
|
204
|
-
end.
|
227
|
+
end.define_model do
|
205
228
|
validates :name, presence: true
|
206
229
|
end
|
207
230
|
|
@@ -218,7 +241,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
218
241
|
def test_global_ignore_tables
|
219
242
|
create_table(:users) do |t|
|
220
243
|
t.string :name, null: true
|
221
|
-
end.
|
244
|
+
end.define_model do
|
222
245
|
validates :name, presence: true
|
223
246
|
end
|
224
247
|
|
@@ -234,7 +257,7 @@ class ActiveRecordDoctor::Detectors::MissingNonNullConstraintTest < Minitest::Te
|
|
234
257
|
def test_config_ignore_columns
|
235
258
|
create_table(:users) do |t|
|
236
259
|
t.string :name, null: true
|
237
|
-
end.
|
260
|
+
end.define_model do
|
238
261
|
validates :name, presence: true
|
239
262
|
end
|
240
263
|
|
@@ -4,7 +4,7 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
4
4
|
def test_null_column_is_not_reported_if_validation_absent
|
5
5
|
create_table(:users) do |t|
|
6
6
|
t.string :name
|
7
|
-
end.
|
7
|
+
end.define_model do
|
8
8
|
end
|
9
9
|
|
10
10
|
refute_problems
|
@@ -13,18 +13,18 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
13
13
|
def test_non_null_column_is_reported_if_validation_absent
|
14
14
|
create_table(:users) do |t|
|
15
15
|
t.string :name, null: false
|
16
|
-
end.
|
16
|
+
end.define_model do
|
17
17
|
end
|
18
18
|
|
19
19
|
assert_problems(<<~OUTPUT)
|
20
|
-
add a `presence` validator to
|
20
|
+
add a `presence` validator to TransientRecord::Models::User.name - it's NOT NULL but lacks a validator
|
21
21
|
OUTPUT
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_non_null_column_is_not_reported_if_validation_present
|
25
25
|
create_table(:users) do |t|
|
26
26
|
t.string :name, null: false
|
27
|
-
end.
|
27
|
+
end.define_model do
|
28
28
|
validates :name, presence: true
|
29
29
|
end
|
30
30
|
|
@@ -32,10 +32,10 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_non_null_column_is_not_reported_if_association_validation_present
|
35
|
-
create_table(:companies).
|
35
|
+
create_table(:companies).define_model
|
36
36
|
create_table(:users) do |t|
|
37
37
|
t.references :company, null: false
|
38
|
-
end.
|
38
|
+
end.define_model do
|
39
39
|
belongs_to :company, required: true
|
40
40
|
end
|
41
41
|
|
@@ -43,8 +43,8 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_not_null_column_is_not_reported_if_habtm_association
|
46
|
-
create_table(:users).
|
47
|
-
has_and_belongs_to_many :projects, class_name: "
|
46
|
+
create_table(:users).define_model do
|
47
|
+
has_and_belongs_to_many :projects, class_name: "TransientRecord::Models::Project"
|
48
48
|
end
|
49
49
|
|
50
50
|
create_table(:projects_users) do |t|
|
@@ -52,8 +52,8 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
52
52
|
t.bigint :user_id, null: false
|
53
53
|
end
|
54
54
|
|
55
|
-
create_table(:projects).
|
56
|
-
has_and_belongs_to_many :users, class_name: "
|
55
|
+
create_table(:projects).define_model do
|
56
|
+
has_and_belongs_to_many :users, class_name: "TransientRecord::Models::User"
|
57
57
|
end
|
58
58
|
|
59
59
|
refute_problems
|
@@ -62,19 +62,19 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
62
62
|
def test_non_null_boolean_is_reported_if_nil_included
|
63
63
|
create_table(:users) do |t|
|
64
64
|
t.boolean :active, null: false
|
65
|
-
end.
|
65
|
+
end.define_model do
|
66
66
|
validates :active, inclusion: { in: [nil, true, false] }
|
67
67
|
end
|
68
68
|
|
69
69
|
assert_problems(<<~OUTPUT)
|
70
|
-
add a `presence` validator to
|
70
|
+
add a `presence` validator to TransientRecord::Models::User.active - it's NOT NULL but lacks a validator
|
71
71
|
OUTPUT
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_non_null_boolean_is_not_reported_if_nil_not_included
|
75
75
|
create_table(:users) do |t|
|
76
76
|
t.boolean :active, null: false
|
77
|
-
end.
|
77
|
+
end.define_model do
|
78
78
|
validates :active, inclusion: { in: [true, false] }
|
79
79
|
end
|
80
80
|
|
@@ -84,22 +84,42 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
84
84
|
def test_non_null_boolean_is_not_reported_if_nil_excluded
|
85
85
|
create_table(:users) do |t|
|
86
86
|
t.boolean :active, null: false
|
87
|
-
end.
|
87
|
+
end.define_model do
|
88
88
|
validates :active, exclusion: { in: [nil] }
|
89
89
|
end
|
90
90
|
|
91
91
|
refute_problems
|
92
92
|
end
|
93
93
|
|
94
|
+
def test_non_null_boolean_is_not_reported_if_exclusion_is_proc
|
95
|
+
create_table(:users) do |t|
|
96
|
+
t.boolean :active, null: false
|
97
|
+
end.define_model do
|
98
|
+
validates :active, exclusion: { in: ->(_user) { [nil] } }
|
99
|
+
end
|
100
|
+
|
101
|
+
refute_problems
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_non_null_boolean_is_not_reported_if_inclusion_is_proc
|
105
|
+
create_table(:users) do |t|
|
106
|
+
t.boolean :active, null: false
|
107
|
+
end.define_model do
|
108
|
+
validates :active, inclusion: { in: ->(_user) { [true, false] } }
|
109
|
+
end
|
110
|
+
|
111
|
+
refute_problems
|
112
|
+
end
|
113
|
+
|
94
114
|
def test_non_null_boolean_is_reported_if_nil_not_excluded
|
95
115
|
create_table(:users) do |t|
|
96
116
|
t.boolean :active, null: false
|
97
|
-
end.
|
117
|
+
end.define_model do
|
98
118
|
validates :active, exclusion: { in: [false] }
|
99
119
|
end
|
100
120
|
|
101
121
|
assert_problems(<<~OUTPUT)
|
102
|
-
add a `presence` validator to
|
122
|
+
add a `presence` validator to TransientRecord::Models::User.active - it's NOT NULL but lacks a validator
|
103
123
|
OUTPUT
|
104
124
|
end
|
105
125
|
|
@@ -113,14 +133,14 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
113
133
|
# errors in some MySQL versions when using t.timestamp.
|
114
134
|
t.datetime :created_on, null: false
|
115
135
|
t.datetime :updated_on, null: false
|
116
|
-
end.
|
136
|
+
end.define_model do
|
117
137
|
end
|
118
138
|
|
119
139
|
refute_problems
|
120
140
|
end
|
121
141
|
|
122
142
|
def test_models_with_non_existent_tables_are_skipped
|
123
|
-
|
143
|
+
define_model(:User)
|
124
144
|
|
125
145
|
refute_problems
|
126
146
|
end
|
@@ -130,14 +150,14 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
130
150
|
|
131
151
|
create_table(:users) do |t|
|
132
152
|
t.string :name
|
133
|
-
end.
|
153
|
+
end.define_model
|
134
154
|
|
135
155
|
ActiveRecord::Base.connection.execute(<<-SQL)
|
136
156
|
ALTER TABLE users ADD CONSTRAINT name_not_null CHECK (name IS NOT NULL)
|
137
157
|
SQL
|
138
158
|
|
139
159
|
assert_problems(<<~OUTPUT)
|
140
|
-
add a `presence` validator to
|
160
|
+
add a `presence` validator to TransientRecord::Models::User.name - it's NOT NULL but lacks a validator
|
141
161
|
OUTPUT
|
142
162
|
end
|
143
163
|
|
@@ -146,7 +166,7 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
146
166
|
|
147
167
|
create_table(:users) do |t|
|
148
168
|
t.string :name
|
149
|
-
end.
|
169
|
+
end.define_model
|
150
170
|
|
151
171
|
ActiveRecord::Base.connection.execute(<<-SQL)
|
152
172
|
ALTER TABLE users ADD CONSTRAINT name_not_null CHECK (name IS NOT NULL) NOT VALID
|
@@ -155,16 +175,24 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
155
175
|
refute_problems
|
156
176
|
end
|
157
177
|
|
178
|
+
def test_abstract_class
|
179
|
+
define_model(:ApplicationRecord) do
|
180
|
+
self.abstract_class = true
|
181
|
+
end
|
182
|
+
|
183
|
+
refute_problems
|
184
|
+
end
|
185
|
+
|
158
186
|
def test_config_ignore_models
|
159
187
|
create_table(:users) do |t|
|
160
188
|
t.string :name, null: false
|
161
|
-
end.
|
189
|
+
end.define_model do
|
162
190
|
end
|
163
191
|
|
164
192
|
config_file(<<-CONFIG)
|
165
193
|
ActiveRecordDoctor.configure do |config|
|
166
194
|
config.detector :missing_presence_validation,
|
167
|
-
ignore_models: ["
|
195
|
+
ignore_models: ["TransientRecord::Models::User"]
|
168
196
|
end
|
169
197
|
CONFIG
|
170
198
|
|
@@ -174,12 +202,12 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
174
202
|
def test_global_ignore_models
|
175
203
|
create_table(:users) do |t|
|
176
204
|
t.string :name, null: false
|
177
|
-
end.
|
205
|
+
end.define_model do
|
178
206
|
end
|
179
207
|
|
180
208
|
config_file(<<-CONFIG)
|
181
209
|
ActiveRecordDoctor.configure do |config|
|
182
|
-
config.global :ignore_models, ["
|
210
|
+
config.global :ignore_models, ["TransientRecord::Models::User"]
|
183
211
|
end
|
184
212
|
CONFIG
|
185
213
|
|
@@ -189,13 +217,13 @@ class ActiveRecordDoctor::Detectors::MissingPresenceValidationTest < Minitest::T
|
|
189
217
|
def test_config_ignore_attributes
|
190
218
|
create_table(:users) do |t|
|
191
219
|
t.string :name, null: false
|
192
|
-
end.
|
220
|
+
end.define_model do
|
193
221
|
end
|
194
222
|
|
195
223
|
config_file(<<-CONFIG)
|
196
224
|
ActiveRecordDoctor.configure do |config|
|
197
225
|
config.detector :missing_presence_validation,
|
198
|
-
ignore_attributes: ["
|
226
|
+
ignore_attributes: ["TransientRecord::Models::User.name"]
|
199
227
|
end
|
200
228
|
CONFIG
|
201
229
|
|
@@ -5,7 +5,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
5
5
|
create_table(:users) do |t|
|
6
6
|
t.string :email
|
7
7
|
t.index :email
|
8
|
-
end.
|
8
|
+
end.define_model do
|
9
9
|
validates :email, uniqueness: true
|
10
10
|
end
|
11
11
|
|
@@ -20,7 +20,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
20
20
|
create_table(:users) do |t|
|
21
21
|
t.string :email
|
22
22
|
t.index "lower(email)"
|
23
|
-
end.
|
23
|
+
end.define_model do
|
24
24
|
validates :email, uniqueness: true
|
25
25
|
end
|
26
26
|
|
@@ -34,7 +34,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
34
34
|
create_table(:users) do |t|
|
35
35
|
t.string :email
|
36
36
|
t.string :ref_token
|
37
|
-
end.
|
37
|
+
end.define_model do
|
38
38
|
validates :email, :ref_token, uniqueness: true
|
39
39
|
end
|
40
40
|
|
@@ -48,7 +48,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
48
48
|
create_table(:users) do |t|
|
49
49
|
t.string :email
|
50
50
|
t.index :email, unique: true
|
51
|
-
end.
|
51
|
+
end.define_model do
|
52
52
|
validates :email, uniqueness: true
|
53
53
|
end
|
54
54
|
|
@@ -62,7 +62,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
62
62
|
t.string :email
|
63
63
|
t.boolean :active
|
64
64
|
t.index :email, unique: true, where: "active"
|
65
|
-
end.
|
65
|
+
end.define_model do
|
66
66
|
validates :email, uniqueness: true
|
67
67
|
end
|
68
68
|
|
@@ -77,7 +77,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
77
77
|
t.integer :company_id
|
78
78
|
t.integer :department_id
|
79
79
|
t.index [:company_id, :department_id, :email]
|
80
|
-
end.
|
80
|
+
end.define_model do
|
81
81
|
validates :email, uniqueness: { scope: [:company_id, :department_id] }
|
82
82
|
end
|
83
83
|
|
@@ -92,7 +92,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
92
92
|
t.integer :company_id
|
93
93
|
t.integer :department_id
|
94
94
|
t.index [:company_id, :department_id, :email], unique: true
|
95
|
-
end.
|
95
|
+
end.define_model do
|
96
96
|
validates :email, uniqueness: { scope: [:company_id, :department_id] }
|
97
97
|
end
|
98
98
|
|
@@ -105,7 +105,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
105
105
|
t.integer :company_id
|
106
106
|
t.integer :department_id
|
107
107
|
t.index [:company_id, :department_id], unique: true
|
108
|
-
end.
|
108
|
+
end.define_model do
|
109
109
|
validates :email, uniqueness: { scope: [:company_id, :department_id] }
|
110
110
|
end
|
111
111
|
|
@@ -115,7 +115,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
115
115
|
def test_missing_unique_index_with_association_attribute
|
116
116
|
create_table(:users) do |t|
|
117
117
|
t.integer :account_id
|
118
|
-
end.
|
118
|
+
end.define_model do
|
119
119
|
belongs_to :account
|
120
120
|
validates :account, uniqueness: true
|
121
121
|
end
|
@@ -129,7 +129,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
129
129
|
create_table(:users) do |t|
|
130
130
|
t.integer :account_id
|
131
131
|
t.index :account_id, unique: true
|
132
|
-
end.
|
132
|
+
end.define_model do
|
133
133
|
belongs_to :account
|
134
134
|
validates :account, uniqueness: true
|
135
135
|
end
|
@@ -142,7 +142,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
142
142
|
t.string :title
|
143
143
|
t.integer :commentable_id
|
144
144
|
t.string :commentable_type
|
145
|
-
end.
|
145
|
+
end.define_model do
|
146
146
|
belongs_to :commentable, polymorphic: true
|
147
147
|
validates :title, uniqueness: { scope: :commentable }
|
148
148
|
end
|
@@ -158,7 +158,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
158
158
|
t.integer :commentable_id
|
159
159
|
t.string :commentable_type
|
160
160
|
t.index [:commentable_id, :commentable_type, :title], unique: true
|
161
|
-
end.
|
161
|
+
end.define_model do
|
162
162
|
belongs_to :commentable, polymorphic: true
|
163
163
|
validates :title, uniqueness: { scope: :commentable }
|
164
164
|
end
|
@@ -172,7 +172,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
172
172
|
t.integer :organization_id
|
173
173
|
|
174
174
|
t.index [:email, :organization_id], unique: true
|
175
|
-
end.
|
175
|
+
end.define_model do
|
176
176
|
validates :email, uniqueness: { scope: :organization_id }
|
177
177
|
end
|
178
178
|
|
@@ -199,7 +199,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
199
199
|
create_table(:users) do |t|
|
200
200
|
t.string :email
|
201
201
|
t.index :email
|
202
|
-
end.
|
202
|
+
end.define_model do
|
203
203
|
validates_with DummyValidator
|
204
204
|
end
|
205
205
|
|
@@ -208,51 +208,51 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
208
208
|
|
209
209
|
def test_has_one_without_index
|
210
210
|
create_table(:users)
|
211
|
-
.
|
212
|
-
has_one :account, class_name: "
|
213
|
-
has_one :account_history, through: :account, class_name: "
|
211
|
+
.define_model do
|
212
|
+
has_one :account, class_name: "TransientRecord::Models::Account"
|
213
|
+
has_one :account_history, through: :account, class_name: "TransientRecord::Models::Account"
|
214
214
|
end
|
215
215
|
|
216
216
|
create_table(:accounts) do |t|
|
217
217
|
t.integer :user_id
|
218
|
-
end.
|
219
|
-
has_one :account_history, class_name: "
|
218
|
+
end.define_model do
|
219
|
+
has_one :account_history, class_name: "TransientRecord::Models::AccountHistory"
|
220
220
|
end
|
221
221
|
|
222
222
|
create_table(:account_histories) do |t|
|
223
223
|
t.integer :account_id
|
224
|
-
end.
|
225
|
-
belongs_to :account, class_name: "
|
224
|
+
end.define_model do
|
225
|
+
belongs_to :account, class_name: "TransientRecord::Models::Account"
|
226
226
|
end
|
227
227
|
|
228
228
|
assert_problems(<<~OUTPUT)
|
229
|
-
add a unique index on accounts(user_id) - using `has_one` in the
|
230
|
-
add a unique index on account_histories(account_id) - using `has_one` in the
|
229
|
+
add a unique index on accounts(user_id) - using `has_one` in the TransientRecord::Models::User model without an index can lead to duplicates
|
230
|
+
add a unique index on account_histories(account_id) - using `has_one` in the TransientRecord::Models::Account model without an index can lead to duplicates
|
231
231
|
OUTPUT
|
232
232
|
end
|
233
233
|
|
234
234
|
def test_has_one_with_scope_and_without_index
|
235
235
|
create_table(:users)
|
236
|
-
.
|
237
|
-
has_one :last_comment, -> { order(created_at: :desc) }, class_name: "
|
236
|
+
.define_model do
|
237
|
+
has_one :last_comment, -> { order(created_at: :desc) }, class_name: "TransientRecord::Models::Comment"
|
238
238
|
end
|
239
239
|
|
240
240
|
create_table(:comments) do |t|
|
241
241
|
t.integer :user_id
|
242
|
-
end.
|
242
|
+
end.define_model
|
243
243
|
|
244
244
|
refute_problems
|
245
245
|
end
|
246
246
|
|
247
247
|
def test_has_one_with_index
|
248
248
|
create_table(:users)
|
249
|
-
.
|
250
|
-
has_one :account, class_name: "
|
249
|
+
.define_model do
|
250
|
+
has_one :account, class_name: "TransientRecord::Models::Account"
|
251
251
|
end
|
252
252
|
|
253
253
|
create_table(:accounts) do |t|
|
254
254
|
t.integer :user_id, index: { unique: true }
|
255
|
-
end.
|
255
|
+
end.define_model
|
256
256
|
|
257
257
|
refute_problems
|
258
258
|
end
|
@@ -260,14 +260,14 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
260
260
|
def test_config_ignore_models
|
261
261
|
create_table(:users) do |t|
|
262
262
|
t.string :email
|
263
|
-
end.
|
263
|
+
end.define_model do
|
264
264
|
validates :email, uniqueness: true
|
265
265
|
end
|
266
266
|
|
267
267
|
config_file(<<-CONFIG)
|
268
268
|
ActiveRecordDoctor.configure do |config|
|
269
269
|
config.detector :missing_unique_indexes,
|
270
|
-
ignore_models: ["
|
270
|
+
ignore_models: ["TransientRecord::Models::User"]
|
271
271
|
end
|
272
272
|
CONFIG
|
273
273
|
|
@@ -277,13 +277,13 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
277
277
|
def test_global_ignore_models
|
278
278
|
create_table(:users) do |t|
|
279
279
|
t.string :email
|
280
|
-
end.
|
280
|
+
end.define_model do
|
281
281
|
validates :email, uniqueness: true
|
282
282
|
end
|
283
283
|
|
284
284
|
config_file(<<-CONFIG)
|
285
285
|
ActiveRecordDoctor.configure do |config|
|
286
|
-
config.global :ignore_models, ["
|
286
|
+
config.global :ignore_models, ["TransientRecord::Models::User"]
|
287
287
|
end
|
288
288
|
CONFIG
|
289
289
|
|
@@ -294,14 +294,14 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
294
294
|
create_table(:users) do |t|
|
295
295
|
t.string :email
|
296
296
|
t.integer :role
|
297
|
-
end.
|
297
|
+
end.define_model do
|
298
298
|
validates :email, :role, uniqueness: { scope: :organization_id }
|
299
299
|
end
|
300
300
|
|
301
301
|
config_file(<<-CONFIG)
|
302
302
|
ActiveRecordDoctor.configure do |config|
|
303
303
|
config.detector :missing_unique_indexes,
|
304
|
-
ignore_columns: ["
|
304
|
+
ignore_columns: ["TransientRecord::Models::User(organization_id, email)", "TransientRecord::Models::User(organization_id, role)"]
|
305
305
|
end
|
306
306
|
CONFIG
|
307
307
|
|
@@ -318,7 +318,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
|
|
318
318
|
def assert_skipped(options)
|
319
319
|
create_table(:users) do |t|
|
320
320
|
t.string :email
|
321
|
-
end.
|
321
|
+
end.define_model do
|
322
322
|
validates :email, uniqueness: options
|
323
323
|
end
|
324
324
|
|