Skip to content

Commit f960dc6

Browse files
committed
Add detector
1 parent 96b3dd6 commit f960dc6

File tree

5 files changed

+109
-0
lines changed

5 files changed

+109
-0
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ can detect:
1717
* mismatched foreign key types - [`active_record_doctor:mismatched_foreign_key_type`](#detecting-mismatched-foreign-key-types)
1818
* tables without primary keys - [`active_record_doctor:table_without_primary_key`](#detecting-tables-without-primary-keys)
1919
* tables without timestamps - [`active_record_doctor:table_without_timestamps`](#detecting-tables-without-timestamps)
20+
* undefined model references - [`active_record_doctor:undefined_model_references](#detecting-undefined-model-references)
2021

2122
It can also:
2223

@@ -664,6 +665,27 @@ Supported configuration options:
664665
- `enabled` - set to `false` to disable the detector altogether
665666
- `ignore_tables` - tables whose timestamp columns existence should not be checked
666667

668+
### Detecting Undefined Model References
669+
670+
When a table is no longer used by the application, it should usually be dropped from the database.
671+
672+
Running the command below will list all tables without default timestamp columns:
673+
674+
```
675+
bundle exec rake active_record_doctor:undefined_model_references
676+
```
677+
678+
The output of the command looks like this:
679+
680+
```
681+
The users table is not referenced by a Rails model. If you are in the process of migrating it away, temporarily ignore it by adding it to the `ignore_tables` configuration and then remove it after the ruby code no longer uses it. Remember, do not delete the table until your deployed application code no longer uses it.
682+
```
683+
684+
Supported configuration options:
685+
686+
- `enabled` - set to `false` to disable the detector altogether
687+
- `ignore_tables` - tables that are not represented by models but cannot yet be dropped from the database (i.e. because the deployed version of the code may still be reading it)
688+
667689
## Ruby and Rails Compatibility Policy
668690

669691
The goal of the policy is to ensure proper functioning in reasonable

lib/active_record_doctor.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
require "active_record_doctor/detectors/mismatched_foreign_key_type"
2323
require "active_record_doctor/detectors/table_without_primary_key"
2424
require "active_record_doctor/detectors/table_without_timestamps"
25+
require "active_record_doctor/detectors/undefined_model_references"
2526
require "active_record_doctor/errors"
2627
require "active_record_doctor/help"
2728
require "active_record_doctor/runner"

lib/active_record_doctor/config/default.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,8 @@
8383
enabled: true,
8484
ignore_tables: [],
8585
ignore_columns: []
86+
87+
detector :undefined_model_references,
88+
enabled: true,
89+
ignore_tables: []
8690
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
require 'active_record_doctor/detectors/base'
4+
5+
module ActiveRecordDoctor
6+
module Detectors
7+
class UndefinedModelReferences < Base # :nodoc:
8+
@description = 'detect tables not referenced by any model'
9+
@config = {
10+
ignore_tables: {
11+
description: 'tables whose corresponding models should not be checked for existence',
12+
global: true
13+
}
14+
}
15+
16+
private
17+
18+
def message(table:, **)
19+
"The #{table} table is not referenced by a Rails model. If you are in the process of migrating it away, temporarily ignore it " \
20+
'by adding it to the `ignore_tables` configuration and then remove it after the ruby code no longer uses it. ' \
21+
'Remember, do not delete the table until your deployed application code no longer uses it.'
22+
end
23+
24+
def detect
25+
each_table(except: config(:ignore_tables)) do |table|
26+
matching_model = ActiveRecord::Base.descendants.find do |model|
27+
model.table_name == table
28+
end
29+
30+
problem!(table:) if matching_model.nil?
31+
end
32+
end
33+
end
34+
end
35+
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
class ActiveRecordDoctor::Detectors::UndefinedModelReferencesTest < Minitest::Test
4+
def test_table_with_model
5+
Context.create_table(:users) do
6+
end.define_model do
7+
end
8+
9+
refute_problems
10+
end
11+
12+
def test_table_without_model
13+
Context.create_table(:users) do
14+
end
15+
16+
assert_problems(<<~OUTPUT)
17+
The users table is not referenced by a Rails model. If you are in the process of migrating it away, temporarily ignore it by adding it to the `ignore_tables` configuration and then remove it after the ruby code no longer uses it. Remember, do not delete the table until your deployed application code no longer uses it.
18+
OUTPUT
19+
end
20+
21+
def test_config_ignore_tables
22+
Context.create_table(:users) do
23+
end
24+
25+
config_file(<<-CONFIG)
26+
ActiveRecordDoctor.configure do |config|
27+
config.detector :undefined_model_references,
28+
ignore_tables: ["users"]
29+
end
30+
CONFIG
31+
32+
refute_problems
33+
end
34+
35+
def test_global_ignore_tables
36+
Context.create_table(:users) do
37+
end
38+
39+
config_file(<<-CONFIG)
40+
ActiveRecordDoctor.configure do |config|
41+
config.global :ignore_tables, ["users"]
42+
end
43+
CONFIG
44+
45+
refute_problems
46+
end
47+
end

0 commit comments

Comments
 (0)