active_record_doctor 1.7.1 → 1.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -9
- data/lib/active_record_doctor.rb +15 -1
- data/lib/active_record_doctor/printers/io_printer.rb +3 -3
- data/lib/active_record_doctor/tasks.rb +3 -0
- data/lib/active_record_doctor/tasks/base.rb +10 -2
- data/lib/active_record_doctor/tasks/extraneous_indexes.rb +2 -0
- data/lib/active_record_doctor/tasks/incorrect_boolean_presence_validation.rb +5 -1
- data/lib/active_record_doctor/tasks/missing_foreign_keys.rb +2 -0
- data/lib/active_record_doctor/tasks/missing_non_null_constraint.rb +5 -1
- data/lib/active_record_doctor/tasks/missing_presence_validation.rb +5 -1
- data/lib/active_record_doctor/tasks/missing_unique_indexes.rb +4 -3
- data/lib/active_record_doctor/tasks/undefined_table_references.rb +2 -0
- data/lib/active_record_doctor/tasks/unindexed_deleted_at.rb +6 -2
- data/lib/active_record_doctor/tasks/unindexed_foreign_keys.rb +2 -0
- data/lib/active_record_doctor/version.rb +1 -1
- data/lib/tasks/active_record_doctor.rake +1 -0
- data/test/active_record_doctor/printers/io_printer_test.rb +11 -3
- data/test/active_record_doctor/tasks/extraneous_indexes_test.rb +1 -5
- data/test/active_record_doctor/tasks/incorrect_boolean_presence_validation_test.rb +10 -5
- data/test/active_record_doctor/tasks/missing_foreign_keys_test.rb +1 -5
- data/test/active_record_doctor/tasks/missing_non_null_constraint_test.rb +10 -5
- data/test/active_record_doctor/tasks/missing_presence_validation_test.rb +10 -5
- data/test/active_record_doctor/tasks/missing_unique_indexes_test.rb +36 -5
- data/test/active_record_doctor/tasks/undefined_table_references_test.rb +1 -5
- data/test/active_record_doctor/tasks/unindexed_deleted_at_test.rb +30 -5
- data/test/active_record_doctor/tasks/unindexed_foreign_keys_test.rb +1 -5
- data/test/setup.rb +97 -0
- metadata +16 -104
- data/Rakefile +0 -28
- data/test/dummy/README.rdoc +0 -28
- data/test/dummy/Rakefile +0 -6
- data/test/dummy/app/assets/config/manifest.js +0 -1
- data/test/dummy/app/assets/javascripts/application.js +0 -13
- data/test/dummy/app/assets/stylesheets/application.css +0 -15
- data/test/dummy/app/controllers/application_controller.rb +0 -5
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/models/application_record.rb +0 -3
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/bin/bundle +0 -3
- data/test/dummy/bin/rails +0 -4
- data/test/dummy/bin/rake +0 -4
- data/test/dummy/bin/setup +0 -29
- data/test/dummy/config.ru +0 -4
- data/test/dummy/config/application.rb +0 -23
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/database.yml +0 -19
- data/test/dummy/config/database.yml.travis +0 -5
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -41
- data/test/dummy/config/environments/production.rb +0 -79
- data/test/dummy/config/environments/test.rb +0 -47
- data/test/dummy/config/initializers/assets.rb +0 -11
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
- data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/initializers/mime_types.rb +0 -4
- data/test/dummy/config/initializers/session_store.rb +0 -3
- data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/test/dummy/config/locales/en.yml +0 -23
- data/test/dummy/config/routes.rb +0 -56
- data/test/dummy/config/secrets.yml +0 -22
- data/test/dummy/db/migrate/base_migration.rb +0 -5
- data/test/dummy/db/schema.rb +0 -19
- data/test/dummy/log/development.log +0 -111
- data/test/dummy/log/test.log +0 -79424
- data/test/dummy/public/404.html +0 -67
- data/test/dummy/public/422.html +0 -67
- data/test/dummy/public/500.html +0 -66
- data/test/dummy/public/favicon.ico +0 -0
- data/test/support/assertions.rb +0 -11
- data/test/support/temping.rb +0 -25
- data/test/test_helper.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 649707d9a4a22831b3733778ad05614cc71f8edb704a68e9b18bd784a350daf9
|
4
|
+
data.tar.gz: 6e0fc8fe22ba882549152203c3a92f3eeebd3effb3f4eead6245001849b9e5de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 437df56684da87b78b3336337cabe138f5375c54673a5d02da29b06fa9d238e1c9fa34a4cf9973b7bf944a0ef8ebbed5ec9dd9d9d12612f87e16597292ff22aa
|
7
|
+
data.tar.gz: 3ee83bab9d6dc5c88c4c47d33d69d30ecf373bb6ab4798accfc681066fd0a1a4580295f29a869c69a9ff582c925f7c2cb328b345429a92623942995a0416e1d6
|
data/README.md
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
Active Record Doctor helps to keep the database in a good shape. Currently, it
|
4
4
|
can:
|
5
5
|
|
6
|
-
* index unindexed foreign keys
|
7
|
-
* detect extraneous indexes
|
8
|
-
* detect unindexed `deleted_at` columns
|
9
|
-
* detect missing foreign key constraints
|
10
|
-
* detect models referencing undefined tables
|
11
|
-
* detect uniqueness validations not backed by an unique index
|
12
|
-
* detect missing non-`NULL` constraints
|
13
|
-
* detect missing presence validations
|
14
|
-
* detect incorrect presence validations on boolean columns
|
6
|
+
* index unindexed foreign keys - [`active_record_doctor:unindexed_foreign_keys`](#indexing-unindexed-foreign-keys)
|
7
|
+
* detect extraneous indexes - [`active_record_doctor:extraneous_indexes`](#removing-extraneous-indexes)
|
8
|
+
* detect unindexed `deleted_at` columns - [`active_record_doctor:unindexed_deleted_at`](#detecting-unindexed-deleted_at-columns)
|
9
|
+
* detect missing foreign key constraints - [`active_record_doctor:missing_foreign_keys`](#detecting-missing-foreign-key-constraints)
|
10
|
+
* detect models referencing undefined tables - [`active_record_doctor:undefined_table_references`](#detecting-models-referencing-undefined-tables)
|
11
|
+
* detect uniqueness validations not backed by an unique index - [`active_record_doctor:missing_unique_indexes`](#detecting-uniqueness-validations-not-backed-by-an-index)
|
12
|
+
* detect missing non-`NULL` constraints - [`active_record_doctor:missing_non_null_constraint`](#detecting-missing-non-null-constraints)
|
13
|
+
* detect missing presence validations - [`active_record_doctor:missing_presence_validation`](#detecting-missing-presence-validations)
|
14
|
+
* detect incorrect presence validations on boolean columns - [`active_record_doctor:incorrect_boolean_presence_validation`](#detecting-incorrect-presence-validations-on-boolean-columns)
|
15
15
|
|
16
16
|
More features coming soon!
|
17
17
|
|
@@ -237,6 +237,8 @@ The following columns should be marked as `null: false`:
|
|
237
237
|
You can mark the columns mentioned in the output as `null: false` by creating a
|
238
238
|
migration and calling `change_column_null`.
|
239
239
|
|
240
|
+
This validator skips models whose corresponding database tables don't exist.
|
241
|
+
|
240
242
|
### Detecting Missing Presence Validations
|
241
243
|
|
242
244
|
If a column is marked as `null: false` then it's likely it should have the
|
@@ -257,6 +259,8 @@ The following models and columns should have presence validations:
|
|
257
259
|
|
258
260
|
This means `User` should have a presence validator on `email` and `name`.
|
259
261
|
|
262
|
+
This validator skips models whose corresponding database tables don't exist.
|
263
|
+
|
260
264
|
### Detecting Incorrect Presence Validations on Boolean Columns
|
261
265
|
|
262
266
|
A boolean column's presence should be validated using inclusion or exclusion
|
@@ -278,6 +282,19 @@ The presence of the following boolean columns is validated incorrectly:
|
|
278
282
|
This means `active` is validated with `presence: true` instead of
|
279
283
|
`inclusion: { in: [true, false] }` or `exclusion: { in: [nil] }`.
|
280
284
|
|
285
|
+
This validator skips models whose corresponding database tables don't exist.
|
286
|
+
|
287
|
+
## Ruby and Rails Compatibility Policy
|
288
|
+
|
289
|
+
The goal of the policy is to ensure proper functioning in reasonable
|
290
|
+
combinations of Ruby and Rails versions. Specifically:
|
291
|
+
|
292
|
+
1. If a Rails version is officially supported by the Rails Core Team then it's
|
293
|
+
supported by `active_record_doctor`.
|
294
|
+
2. If a Ruby version is compatible with a supported Rails version then it's
|
295
|
+
also supported by `active_record_doctor`.
|
296
|
+
3. Only most recent teeny Ruby versions and patch Rails versions are supported.
|
297
|
+
|
281
298
|
## Author
|
282
299
|
|
283
300
|
This gem is developed and maintained by [Greg Navis](http://www.gregnavis.com).
|
data/lib/active_record_doctor.rb
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
require "active_record_doctor/
|
1
|
+
require "active_record_doctor/printers"
|
2
|
+
require "active_record_doctor/printers/io_printer"
|
3
|
+
require "active_record_doctor/railtie" if defined?(Rails) && defined?(Rails::Railtie)
|
4
|
+
require "active_record_doctor/tasks"
|
5
|
+
require "active_record_doctor/tasks/base"
|
6
|
+
require "active_record_doctor/tasks/missing_presence_validation"
|
7
|
+
require "active_record_doctor/tasks/missing_foreign_keys"
|
8
|
+
require "active_record_doctor/tasks/missing_unique_indexes"
|
9
|
+
require "active_record_doctor/tasks/incorrect_boolean_presence_validation"
|
10
|
+
require "active_record_doctor/tasks/extraneous_indexes"
|
11
|
+
require "active_record_doctor/tasks/unindexed_deleted_at"
|
12
|
+
require "active_record_doctor/tasks/undefined_table_references"
|
13
|
+
require "active_record_doctor/tasks/missing_non_null_constraint"
|
14
|
+
require "active_record_doctor/tasks/unindexed_foreign_keys"
|
15
|
+
require "active_record_doctor/version"
|
2
16
|
|
3
17
|
module ActiveRecordDoctor
|
4
18
|
end
|
@@ -92,11 +92,11 @@ EOS
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
def
|
96
|
-
return if
|
95
|
+
def incorrect_boolean_presence_validation(incorrect_boolean_presence_validations)
|
96
|
+
return if incorrect_boolean_presence_validations.empty?
|
97
97
|
|
98
98
|
@io.puts('The presence of the following boolean columns is validated incorrectly:')
|
99
|
-
|
99
|
+
incorrect_boolean_presence_validations.each do |table, columns|
|
100
100
|
@io.puts(" #{table}: #{columns.join(', ')}")
|
101
101
|
end
|
102
102
|
end
|
@@ -7,6 +7,10 @@ module ActiveRecordDoctor
|
|
7
7
|
new.run
|
8
8
|
end
|
9
9
|
|
10
|
+
def self.description
|
11
|
+
@description
|
12
|
+
end
|
13
|
+
|
10
14
|
def initialize(printer = ActiveRecordDoctor::Printers::IOPrinter.new)
|
11
15
|
@printer = printer
|
12
16
|
end
|
@@ -27,16 +31,20 @@ module ActiveRecordDoctor
|
|
27
31
|
|
28
32
|
def tables
|
29
33
|
@tables ||=
|
30
|
-
if
|
34
|
+
if ActiveRecord::VERSION::MAJOR == 5
|
31
35
|
connection.data_sources
|
32
36
|
else
|
33
37
|
connection.tables
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
41
|
+
def table_exists?(table_name)
|
42
|
+
connection.table_exists?(table_name)
|
43
|
+
end
|
44
|
+
|
37
45
|
def views
|
38
46
|
@views ||=
|
39
|
-
if
|
47
|
+
if ActiveRecord::VERSION::MAJOR == 5
|
40
48
|
connection.views
|
41
49
|
elsif connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
42
50
|
ActiveRecord::Base.connection.execute(<<-SQL).map { |tuple| tuple.fetch("relname") }
|
@@ -3,11 +3,15 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class IncorrectBooleanPresenceValidation < Base
|
6
|
+
@description = 'Detect boolean columns with presence/absence instead of includes/excludes validators'
|
7
|
+
|
6
8
|
def run
|
7
9
|
eager_load!
|
8
10
|
|
9
11
|
success(hash_from_pairs(models.reject do |model|
|
10
|
-
model.table_name.nil? ||
|
12
|
+
model.table_name.nil? ||
|
13
|
+
model.table_name == 'schema_migrations' ||
|
14
|
+
!table_exists?(model.table_name)
|
11
15
|
end.map do |model|
|
12
16
|
[
|
13
17
|
model.name,
|
@@ -3,6 +3,8 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class MissingForeignKeys < Base
|
6
|
+
@description = 'Detect association columns without a foreign key constraint'
|
7
|
+
|
6
8
|
def run
|
7
9
|
success(hash_from_pairs(tables.select do |table|
|
8
10
|
"schema_migrations" != table
|
@@ -3,11 +3,15 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class MissingNonNullConstraint < Base
|
6
|
+
@description = 'Detect presence validators not backed by a non-NULL constraint'
|
7
|
+
|
6
8
|
def run
|
7
9
|
eager_load!
|
8
10
|
|
9
11
|
success(hash_from_pairs(models.reject do |model|
|
10
|
-
model.table_name.nil? ||
|
12
|
+
model.table_name.nil? ||
|
13
|
+
model.table_name == 'schema_migrations' ||
|
14
|
+
!table_exists?(model.table_name)
|
11
15
|
end.map do |model|
|
12
16
|
[
|
13
17
|
model.table_name,
|
@@ -3,11 +3,15 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class MissingPresenceValidation < Base
|
6
|
+
@description = 'Detect non-NULL columns without a presence validator'
|
7
|
+
|
6
8
|
def run
|
7
9
|
eager_load!
|
8
10
|
|
9
11
|
success(hash_from_pairs(models.reject do |model|
|
10
|
-
model.table_name.nil? ||
|
12
|
+
model.table_name.nil? ||
|
13
|
+
model.table_name == 'schema_migrations' ||
|
14
|
+
!table_exists?(model.table_name)
|
11
15
|
end.map do |model|
|
12
16
|
[
|
13
17
|
model.name,
|
@@ -3,6 +3,8 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class MissingUniqueIndexes < Base
|
6
|
+
@description = 'Detect columns covered by a uniqueness validator without a unique index'
|
7
|
+
|
6
8
|
def run
|
7
9
|
eager_load!
|
8
10
|
|
@@ -13,12 +15,11 @@ module ActiveRecordDoctor
|
|
13
15
|
model.table_name,
|
14
16
|
model.validators.select do |validator|
|
15
17
|
table_name = model.table_name
|
16
|
-
attributes = validator.attributes
|
17
18
|
scope = validator.options.fetch(:scope, [])
|
18
19
|
|
19
20
|
validator.is_a?(ActiveRecord::Validations::UniquenessValidator) &&
|
20
21
|
supported_validator?(validator) &&
|
21
|
-
!unique_index?(table_name, attributes, scope)
|
22
|
+
!unique_index?(table_name, validator.attributes, scope)
|
22
23
|
end.map do |validator|
|
23
24
|
scope = Array(validator.options.fetch(:scope, []))
|
24
25
|
attributes = validator.attributes
|
@@ -48,7 +49,7 @@ module ActiveRecordDoctor
|
|
48
49
|
columns = (Array(scope) + columns).map(&:to_s)
|
49
50
|
|
50
51
|
indexes(table_name).any? do |index|
|
51
|
-
index.columns == columns && index.unique
|
52
|
+
index.columns.to_set == columns.to_set && index.unique
|
52
53
|
end
|
53
54
|
end
|
54
55
|
end
|
@@ -3,12 +3,16 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class UnindexedDeletedAt < Base
|
6
|
+
COLUMNS = %w[deleted_at discarded_at].freeze
|
7
|
+
PATTERN = COLUMNS.join('|').freeze
|
8
|
+
@description = 'Detect unindexed deleted_at columns'
|
9
|
+
|
6
10
|
def run
|
7
11
|
success(connection.tables.select do |table|
|
8
|
-
connection.columns(table).
|
12
|
+
connection.columns(table).any? { |column| column.name =~ /^#{PATTERN}$/ }
|
9
13
|
end.flat_map do |table|
|
10
14
|
connection.indexes(table).reject do |index|
|
11
|
-
index.where =~ /\
|
15
|
+
index.where =~ /\b#{PATTERN}\s+IS\s+NULL\b/i
|
12
16
|
end.map do |index|
|
13
17
|
index.name
|
14
18
|
end
|
@@ -3,6 +3,8 @@ require "active_record_doctor/tasks/base"
|
|
3
3
|
module ActiveRecordDoctor
|
4
4
|
module Tasks
|
5
5
|
class UnindexedForeignKeys < Base
|
6
|
+
@description = 'Detect foreign keys without an index on them'
|
7
|
+
|
6
8
|
def run
|
7
9
|
success(hash_from_pairs(tables.select do |table|
|
8
10
|
"schema_migrations" != table
|
@@ -1,8 +1,16 @@
|
|
1
|
-
|
1
|
+
# Load all tasks
|
2
|
+
class ActiveRecordDoctor::Printers::IOPrinterTest < Minitest::Test
|
3
|
+
def test_all_tasks_have_printers
|
4
|
+
ActiveRecordDoctor::Tasks::Base.subclasses.each do |task_class|
|
5
|
+
name = task_class.name.demodulize.underscore.to_sym
|
2
6
|
|
3
|
-
|
7
|
+
assert(
|
8
|
+
ActiveRecordDoctor::Printers::IOPrinter.method_defined?(name),
|
9
|
+
"IOPrinter should define #{name}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
4
13
|
|
5
|
-
class ActiveRecordDoctor::Printers::IOPrinterTest < ActiveSupport::TestCase
|
6
14
|
def test_unindexed_foreign_keys
|
7
15
|
assert_equal(<<EOF, unindexed_foreign_keys({ "users" => ["profile_id", "account_id"], "account" => ["group_id"] }))
|
8
16
|
account group_id
|
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_record_doctor/tasks/extraneous_indexes'
|
4
|
-
|
5
|
-
class ActiveRecordDoctor::Tasks::ExtraneousIndexesTest < ActiveSupport::TestCase
|
1
|
+
class ActiveRecordDoctor::Tasks::ExtraneousIndexesTest < Minitest::Test
|
6
2
|
def test_index_on_primary_key_is_duplicate
|
7
3
|
Temping.create(:user, temporary: false) do
|
8
4
|
with_columns do |t|
|
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_record_doctor/tasks/incorrect_boolean_presence_validation'
|
4
|
-
|
5
|
-
class ActiveRecordDoctor::Tasks::IncorrectBooleanPresenceValidationTest < ActiveSupport::TestCase
|
1
|
+
class ActiveRecordDoctor::Tasks::IncorrectBooleanPresenceValidationTest < Minitest::Test
|
6
2
|
def test_presence_true_is_reported_on_boolean_only
|
7
3
|
Temping.create(:users, temporary: false) do
|
8
4
|
# email is a non-boolean column whose presence CAN be validated in the
|
@@ -30,4 +26,13 @@ class ActiveRecordDoctor::Tasks::IncorrectBooleanPresenceValidationTest < Active
|
|
30
26
|
|
31
27
|
assert_equal({}, run_task)
|
32
28
|
end
|
29
|
+
|
30
|
+
def test_models_with_non_existent_tables_are_skipped
|
31
|
+
klass = Class.new(ActiveRecord::Base) do
|
32
|
+
self.table_name = 'action_text_rich_texts'
|
33
|
+
end
|
34
|
+
|
35
|
+
# No need to assert anything as merely not raising an exception is a success.
|
36
|
+
run_task
|
37
|
+
end
|
33
38
|
end
|
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_record_doctor/tasks/missing_foreign_keys'
|
4
|
-
|
5
|
-
class ActiveRecordDoctor::Tasks::MissingForeignKeysTest < ActiveSupport::TestCase
|
1
|
+
class ActiveRecordDoctor::Tasks::MissingForeignKeysTest < Minitest::Test
|
6
2
|
def test_missing_foreign_key_is_reported
|
7
3
|
Temping.create(:companies, temporary: false)
|
8
4
|
Temping.create(:users, temporary: false) do
|
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_record_doctor/tasks/missing_non_null_constraint'
|
4
|
-
|
5
|
-
class ActiveRecordDoctor::Tasks::MissingNonNullConstraintTest < ActiveSupport::TestCase
|
1
|
+
class ActiveRecordDoctor::Tasks::MissingNonNullConstraintTest < Minitest::Test
|
6
2
|
def test_presence_true_and_null_true
|
7
3
|
Temping.create(:users, temporary: false) do
|
8
4
|
validates :name, presence: true
|
@@ -105,4 +101,13 @@ class ActiveRecordDoctor::Tasks::MissingNonNullConstraintTest < ActiveSupport::T
|
|
105
101
|
|
106
102
|
assert_equal({}, run_task)
|
107
103
|
end
|
104
|
+
|
105
|
+
def test_models_with_non_existent_tables_are_skipped
|
106
|
+
klass = Class.new(ActiveRecord::Base) do
|
107
|
+
self.table_name = 'action_text_rich_texts'
|
108
|
+
end
|
109
|
+
|
110
|
+
# No need to assert anything as merely not raising an exception is a success.
|
111
|
+
run_task
|
112
|
+
end
|
108
113
|
end
|
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_record_doctor/tasks/missing_presence_validation'
|
4
|
-
|
5
|
-
class ActiveRecordDoctor::Tasks::MissingPresenceValidationTest < ActiveSupport::TestCase
|
1
|
+
class ActiveRecordDoctor::Tasks::MissingPresenceValidationTest < Minitest::Test
|
6
2
|
def test_null_column_is_not_reported_if_validation_absent
|
7
3
|
Temping.create(:users, temporary: false) do
|
8
4
|
with_columns do |t|
|
@@ -107,4 +103,13 @@ class ActiveRecordDoctor::Tasks::MissingPresenceValidationTest < ActiveSupport::
|
|
107
103
|
|
108
104
|
assert_equal({}, run_task)
|
109
105
|
end
|
106
|
+
|
107
|
+
def test_models_with_non_existent_tables_are_skipped
|
108
|
+
klass = Class.new(ActiveRecord::Base) do
|
109
|
+
self.table_name = 'action_text_rich_texts'
|
110
|
+
end
|
111
|
+
|
112
|
+
# No need to assert anything as merely not raising an exception is a success.
|
113
|
+
run_task
|
114
|
+
end
|
110
115
|
end
|
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_record_doctor/tasks/missing_unique_indexes'
|
4
|
-
|
5
|
-
class ActiveRecordDoctor::Tasks::MissingUniqueIndexesTest < ActiveSupport::TestCase
|
1
|
+
class ActiveRecordDoctor::Tasks::MissingUniqueIndexesTest < Minitest::Test
|
6
2
|
def test_missing_unique_index
|
7
3
|
Temping.create(:users, temporary: false) do
|
8
4
|
with_columns do |t|
|
@@ -63,6 +59,21 @@ class ActiveRecordDoctor::Tasks::MissingUniqueIndexesTest < ActiveSupport::TestC
|
|
63
59
|
assert_result([])
|
64
60
|
end
|
65
61
|
|
62
|
+
def test_column_order_is_ignored
|
63
|
+
Temping.create(:users, temporary: false) do
|
64
|
+
with_columns do |t|
|
65
|
+
t.string :email
|
66
|
+
t.integer :organization_id
|
67
|
+
|
68
|
+
t.index [:email, :organization_id], unique: true
|
69
|
+
end
|
70
|
+
|
71
|
+
validates :email, uniqueness: { scope: :organization_id }
|
72
|
+
end
|
73
|
+
|
74
|
+
assert_result([])
|
75
|
+
end
|
76
|
+
|
66
77
|
def test_conditions_is_skipped
|
67
78
|
assert_skipped(conditions: -> { where.not(email: nil) })
|
68
79
|
end
|
@@ -79,6 +90,26 @@ class ActiveRecordDoctor::Tasks::MissingUniqueIndexesTest < ActiveSupport::TestC
|
|
79
90
|
assert_skipped(unless: ->(model) { true })
|
80
91
|
end
|
81
92
|
|
93
|
+
def test_skips_validator_without_attributes
|
94
|
+
Temping.create(:users, temporary: false) do
|
95
|
+
with_columns do |t|
|
96
|
+
t.string :email
|
97
|
+
t.index :email
|
98
|
+
end
|
99
|
+
|
100
|
+
validates_with DummyValidator
|
101
|
+
end
|
102
|
+
|
103
|
+
# There's no need for assert/refute as it's enough the line below doesn't
|
104
|
+
# raise an exception.
|
105
|
+
run_task
|
106
|
+
end
|
107
|
+
|
108
|
+
class DummyValidator < ActiveModel::Validator
|
109
|
+
def validate(record)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
82
113
|
private
|
83
114
|
|
84
115
|
def assert_skipped(options)
|