active_record_doctor 1.10.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 +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
|
|