active_record_doctor 2.0.0 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bae986a04fe63835ce7e190f32471cc06a370972161c487cac195ef33f73269
4
- data.tar.gz: c5a2f92f0b31ec1faedfd65fc5abe9ef656f75b9fa933719e57f180b4fb0f28d
3
+ metadata.gz: 7c93e45a93d9c11392978f37626379bd322e4827aac59ca6f51400e33a009813
4
+ data.tar.gz: e3e920647f6b68fdec23d7e23e7e4ff3653cb8823673e56b0916d1247cbb3864
5
5
  SHA512:
6
- metadata.gz: 7759e1effdfcea2382966f8973c2c132bda909b847a14914fb7a46b795a7d0407f9605efa39dfece9d889ee65b35f334f78e6664928fbbe03e349f792845ae7f
7
- data.tar.gz: c563de0bbf91966325eddd2bafedb3dadcc07ca39e7c27a529fdb544113eadba4f2373e9d618a074205a8716687f7684f232a212711fcf5d50fc1484999b1074
6
+ metadata.gz: 54c002741991dc91c4afd46de5472d64be0ba02457d23df39bd16297a12f4192023679d281d9bc353a5de5a0c357ea960666967d820316fe5fdaceee36f99d6d
7
+ data.tar.gz: bb17cb57cc708b9d7e751bb79e341aac2df4de4adc5f59d2cf254ef564c0a481b8e8872f1eac34a37246eda9145a78abbb41511150bc064932504645e36453fd
data/README.md CHANGED
@@ -17,6 +17,7 @@ can detect:
17
17
  * mismatched foreign key types - [`active_record_doctor:mismatched_foreign_key_type`](#detecting-mismatched-foreign-key-types)
18
18
  * tables without primary keys - [`active_record_doctor:table_without_primary_key`](#detecting-tables-without-primary-keys)
19
19
  * tables without timestamps - [`active_record_doctor:table_without_timestamps`](#detecting-tables-without-timestamps)
20
+ * unused tables - [`active_record_doctor:unused_tables](#detecting-unused-tables)
20
21
 
21
22
  It can also:
22
23
 
@@ -302,16 +303,15 @@ Supported configuration options:
302
303
 
303
304
  ### Detecting Missing Foreign Key Constraints
304
305
 
305
- If `users.profile_id` references a row in `profiles` then this can be expressed
306
- at the database level with a foreign key constraint. It _forces_
307
- `users.profile_id` to point to an existing row in `profiles`. The problem is
308
- that in many legacy Rails apps, the constraint isn't enforced at the database
309
- level.
306
+ If `User` defines a `belongs_to` association to `Profile` then the underlying
307
+ column (`users.profile_id` by convention) should be marked as a foreign key in
308
+ the database. If it's not then it's possible to end up in a situation where a
309
+ user is referencing a non-existent profile.
310
310
 
311
311
  `active_record_doctor` can automatically detect foreign keys that could benefit
312
312
  from a foreign key constraint (a future version will generate a migration that
313
- add the constraint; for now, it's your job). You can obtain the list of foreign
314
- keys with the following command:
313
+ add the constraint; for now, it's your job). You can obtain the list of missing
314
+ foreign key constraints with the following command:
315
315
 
316
316
  ```bash
317
317
  bundle exec rake active_record_doctor:missing_foreign_keys
@@ -331,9 +331,9 @@ end
331
331
  Supported configuration options:
332
332
 
333
333
  - `enabled` - set to `false` to disable the detector altogether
334
- - `ignore_tables` - tables whose columns should not be checked.
335
- - `ignore_columns` - columns, written as table.column, that should not be
336
- checked.
334
+ - `ignore_models` - models whose associations should not be checked.
335
+ - `ignore_associations` - associations, written as Model.association, that
336
+ should not be checked.
337
337
 
338
338
  ### Detecting Models Referencing Undefined Tables
339
339
 
@@ -666,15 +666,35 @@ Supported configuration options:
666
666
  - `enabled` - set to `false` to disable the detector altogether
667
667
  - `ignore_tables` - tables whose timestamp columns existence should not be checked
668
668
 
669
- ## Ruby and Rails Compatibility Policy
669
+ ### Detecting Unused Tables
670
670
 
671
- The goal of the policy is to ensure proper functioning in reasonable
672
- combinations of Ruby and Rails versions. Specifically:
671
+ **WARNING**: this detector is disabled by default and has to be turned on explicitly.
672
+
673
+ When a table is not used by the application it should usually be dropped from the database.
674
+
675
+ Running the command below will list all tables that are not referenced by any model:
676
+
677
+ ```
678
+ bundle exec rake active_record_doctor:unused_tables
679
+ ```
680
+
681
+ The output of the command looks like this:
682
+
683
+ ```
684
+ The users table is not referenced by any Rails model and can be dropped
685
+ ```
686
+
687
+ Supported configuration options:
688
+
689
+ - `enabled` - set to `true` to enable the detector
690
+ - `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)
691
+
692
+ ## Ruby and Rails Compatibility Policy
673
693
 
674
- 1. If a Rails version is officially supported by the Rails Core Team then it's
694
+ 1. `active_record_doctor` supports all Ruby on Rails versions that are supported
695
+ by the Rails core team.
696
+ 2. If a Ruby version is compatible with a supported Rails version then it's also
675
697
  supported by `active_record_doctor`.
676
- 2. If a Ruby version is compatible with a supported Rails version then it's
677
- also supported by `active_record_doctor`.
678
698
  3. Only the most recent teeny Ruby versions and patch Rails versions are supported.
679
699
 
680
700
  ## Author
@@ -36,8 +36,8 @@ ActiveRecordDoctor.configure do
36
36
 
37
37
  detector :missing_foreign_keys,
38
38
  enabled: true,
39
- ignore_tables: [],
40
- ignore_columns: []
39
+ ignore_models: [],
40
+ ignore_associations: []
41
41
 
42
42
  detector :missing_non_null_constraint,
43
43
  enabled: true,
@@ -83,4 +83,8 @@ ActiveRecordDoctor.configure do
83
83
  enabled: true,
84
84
  ignore_tables: [],
85
85
  ignore_columns: []
86
+
87
+ detector :unused_tables,
88
+ enabled: false,
89
+ ignore_tables: []
86
90
  end
@@ -18,9 +18,12 @@ module ActiveRecordDoctor
18
18
 
19
19
  private
20
20
 
21
- def message(model:, attribute:, table:, database_maximum:, model_maximum:)
21
+ def message(model:, column:, table:, database_maximum:, model_maximum:)
22
+ attribute = column.name
22
23
  # rubocop:disable Layout/LineLength
23
- if database_maximum && model_maximum
24
+ if database_maximum && column.respond_to?(:array?) && column.array?
25
+ "the schema limits each #{table}.#{attribute} array element to #{database_maximum} characters - use a custom validation for this attribute or add it to the ignore list"
26
+ elsif database_maximum && model_maximum
24
27
  "the schema limits #{table}.#{attribute} to #{database_maximum} characters but the length validator on #{model}.#{attribute} enforces a maximum of #{model_maximum} characters - set both limits to the same value or remove both"
25
28
  elsif database_maximum && model_maximum.nil?
26
29
  "the schema limits #{table}.#{attribute} to #{database_maximum} characters but there's no length validator on #{model}.#{attribute} - remove the database limit or add the validator"
@@ -40,7 +43,7 @@ module ActiveRecordDoctor
40
43
 
41
44
  problem!(
42
45
  model: model.name,
43
- attribute: column.name,
46
+ column: column,
44
47
  table: model.table_name,
45
48
  database_maximum: database_maximum,
46
49
  model_maximum: model_maximum
@@ -7,12 +7,12 @@ module ActiveRecordDoctor
7
7
  class MissingForeignKeys < Base # :nodoc:
8
8
  @description = "detect foreign-key-like columns lacking an actual foreign key constraint"
9
9
  @config = {
10
- ignore_tables: {
11
- description: "tables whose columns should not be checked",
10
+ ignore_models: {
11
+ description: "models whose columns should not be checked",
12
12
  global: true
13
13
  },
14
- ignore_columns: {
15
- description: "columns, written as table.column, that should not be checked"
14
+ ignore_associations: {
15
+ description: "associations, written as Model.association, that should not be checked"
16
16
  }
17
17
  }
18
18
 
@@ -23,42 +23,18 @@ module ActiveRecordDoctor
23
23
  end
24
24
 
25
25
  def detect
26
- each_table(except: config(:ignore_tables)) do |table|
27
- each_column(table, except: config(:ignore_columns)) do |column|
28
- # We need to skip polymorphic associations as they can reference
29
- # multiple tables but a foreign key constraint can reference
30
- # a single predefined table.
31
- next unless looks_like_foreign_key?(column)
32
- next if foreign_key?(table, column)
33
- next if polymorphic_foreign_key?(table, column)
34
- next if model_destroyed_async?(table, column)
26
+ each_model(except: config(:ignore_models), existing_tables_only: true) do |model|
27
+ foreign_keys = connection.foreign_keys(model.table_name)
28
+ foreign_key_columns = foreign_keys.map { |key| key.options[:column] }
35
29
 
36
- problem!(table: table, column: column.name)
37
- end
38
- end
39
- end
40
-
41
- def foreign_key?(table, column)
42
- connection.foreign_keys(table).any? do |foreign_key|
43
- foreign_key.options[:column] == column.name
44
- end
45
- end
30
+ each_association(model, type: :belongs_to) do |association|
31
+ next if ignored?("#{model.name}.#{association.name}", config(:ignore_associations))
32
+ next if association.options[:polymorphic]
46
33
 
47
- def polymorphic_foreign_key?(table, column)
48
- type_column_name = column.name.sub(/_id\Z/, "_type")
49
- connection.columns(table).any? do |another_column|
50
- another_column.name == type_column_name
51
- end
52
- end
34
+ has_foreign_key = foreign_key_columns.include?(association.foreign_key)
35
+ next if has_foreign_key
53
36
 
54
- def model_destroyed_async?(table, column)
55
- # Check if there are any models having `has_many ..., dependent: :destroy_async`
56
- # referencing the specified table.
57
- models.any? do |model|
58
- model.reflect_on_all_associations(:has_many).any? do |reflection|
59
- reflection.options[:dependent] == :destroy_async &&
60
- reflection.foreign_key == column.name &&
61
- reflection.klass.table_name == table
37
+ problem!(table: model.table_name, column: association.foreign_key)
62
38
  end
63
39
  end
64
40
  end
@@ -21,14 +21,14 @@ module ActiveRecordDoctor
21
21
 
22
22
  private
23
23
 
24
- def message(type:, column_or_association:, model:)
24
+ def message(type:, column:, reflection:, model:)
25
25
  case type
26
26
  when :missing_validator
27
- "add a `presence` validator to #{model}.#{column_or_association} - it's NOT NULL but lacks a validator"
27
+ "add a `presence` validator to #{model}.#{column} - it's NOT NULL but lacks a validator"
28
28
  when :optional_association
29
- "add `optional: false` to #{model}.#{column_or_association} - the foreign key #{column_or_association}_id is NOT NULL" # rubocop:disable Layout/LineLength
29
+ "add `optional: false` to #{model}.#{reflection.name} - the foreign key #{reflection.foreign_key} is NOT NULL"
30
30
  when :optional_polymorphic_association
31
- "add `optional: false` to #{model}.#{column_or_association} - the foreign key #{column_or_association}_id or type #{column_or_association}_type are NOT NULL" # rubocop:disable Layout/LineLength
31
+ "add `optional: false` to #{model}.#{reflection.name} - the foreign key #{reflection.foreign_key} or type #{reflection.foreign_type} are NOT NULL" # rubocop:disable Layout/LineLength
32
32
  end
33
33
  end
34
34
 
@@ -56,7 +56,7 @@ module ActiveRecordDoctor
56
56
  (config(:ignore_columns_with_default) && (column.default || column.default_function)) ||
57
57
 
58
58
  # Explicitly ignored columns should be skipped.
59
- config(:ignore_attributes).include?("#{model.name}.#{column.name}")
59
+ ignored?("#{model.name}.#{column.name}", config(:ignore_attributes))
60
60
  end
61
61
 
62
62
  # At this point the only columns that are left are those that DO
@@ -76,29 +76,31 @@ module ActiveRecordDoctor
76
76
  # that are validated directly or via an association name.
77
77
  model.validators.each do |validator|
78
78
  problematic_columns.reject! do |column|
79
- # Translate a foreign key or type to the association name.
80
- attribute = column_name_to_association_name[column.name] || column.name.to_sym
79
+ attribute_names = [
80
+ column.name.to_sym,
81
+ column_name_to_association_name[column.name]
82
+ ].compact
81
83
 
82
84
  case validator
83
85
 
84
86
  # A regular presence validator is enough if the column name is
85
87
  # listed among the attributes it's validating.
86
88
  when ActiveRecord::Validations::PresenceValidator
87
- validator.attributes.include?(attribute)
89
+ (validator.attributes & attribute_names).present?
88
90
 
89
91
  # An inclusion validator ensures the column is not nil if it covers
90
92
  # the column and nil is NOT one of the values it allows.
91
93
  when ActiveModel::Validations::InclusionValidator
92
94
  validator_items = inclusion_or_exclusion_validator_items(validator)
93
- validator.attributes.include?(attribute) &&
94
- (validator_items.is_a?(Proc) || validator_items.exclude?(nil))
95
+ (validator.attributes & attribute_names).present? &&
96
+ (dynamic_validator_items?(validator_items) || validator_items.exclude?(nil))
95
97
 
96
98
  # An exclusion validator ensures the column is not nil if it covers
97
99
  # the column and excludes nil as an allowed value explicitly.
98
100
  when ActiveModel::Validations::ExclusionValidator
99
101
  validator_items = inclusion_or_exclusion_validator_items(validator)
100
- validator.attributes.include?(attribute) &&
101
- (validator_items.is_a?(Proc) || validator_items.include?(nil))
102
+ (validator.attributes & attribute_names).present? &&
103
+ (dynamic_validator_items?(validator_items) || validator_items.include?(nil))
102
104
 
103
105
  end
104
106
  end
@@ -109,7 +111,7 @@ module ActiveRecordDoctor
109
111
  problematic_associations = []
110
112
  problematic_polymorphic_associations = []
111
113
 
112
- model.reflect_on_all_associations.each do |reflection|
114
+ model.reflect_on_all_associations(:belongs_to).each do |reflection|
113
115
  foreign_key_column = problematic_columns.find { |column| column.name == reflection.foreign_key }
114
116
  if reflection.polymorphic?
115
117
  # If the foreign key and type are not one of the columns that lack
@@ -125,7 +127,7 @@ module ActiveRecordDoctor
125
127
 
126
128
  # ... report an error about an incorrectly configured polymorphic
127
129
  # association.
128
- problematic_polymorphic_associations << reflection.name
130
+ problematic_polymorphic_associations << reflection
129
131
  else
130
132
  # If the foreign key is not one of the columns that lack a
131
133
  # validator then it means the association added a validator and is
@@ -137,7 +139,7 @@ module ActiveRecordDoctor
137
139
  problematic_columns.delete(foreign_key_column)
138
140
 
139
141
  # ... report an error about an incorrectly configured association.
140
- problematic_associations << reflection.name
142
+ problematic_associations << reflection
141
143
  end
142
144
  end
143
145
 
@@ -145,22 +147,22 @@ module ActiveRecordDoctor
145
147
  # ignored should be removed from the output. It's NOT enough to skip
146
148
  # processing them in the loop above because their underlying foreign
147
149
  # key and type columns must be removed from output, too.
148
- problematic_associations.reject! do |name|
149
- config(:ignore_attributes).include?("#{model.name}.#{name}")
150
+ problematic_associations.reject! do |reflection|
151
+ config(:ignore_attributes).include?("#{model.name}.#{reflection.name}")
150
152
  end
151
- problematic_polymorphic_associations.reject! do |name|
152
- config(:ignore_attributes).include?("#{model.name}.#{name}")
153
+ problematic_polymorphic_associations.reject! do |reflection|
154
+ config(:ignore_attributes).include?("#{model.name}.#{reflection.name}")
153
155
  end
154
156
 
155
157
  # Job is done and all accumulated errors can be reported.
156
- problematic_polymorphic_associations.each do |name|
157
- problem!(type: :optional_polymorphic_association, column_or_association: name, model: model.name)
158
+ problematic_polymorphic_associations.each do |reflection|
159
+ problem!(type: :optional_polymorphic_association, column: nil, reflection: reflection, model: model.name)
158
160
  end
159
- problematic_associations.each do |name|
160
- problem!(type: :optional_association, column_or_association: name, model: model.name)
161
+ problematic_associations.each do |reflection|
162
+ problem!(type: :optional_association, column: nil, reflection: reflection, model: model.name)
161
163
  end
162
164
  problematic_columns.each do |column|
163
- problem!(type: :missing_validator, column_or_association: column.name, model: model.name)
165
+ problem!(type: :missing_validator, column: column.name, reflection: nil, model: model.name)
164
166
  end
165
167
  end
166
168
  end
@@ -170,6 +172,12 @@ module ActiveRecordDoctor
170
172
  validator.options[:in] || validator.options[:within] || []
171
173
  end
172
174
 
175
+ # The allowed values can be a Proc or a method name (Symbol) that's resolved
176
+ # at validation time, so the set of values isn't known statically.
177
+ def dynamic_validator_items?(validator_items)
178
+ validator_items.is_a?(Proc) || validator_items.is_a?(Symbol)
179
+ end
180
+
173
181
  # Determines whether the given column is used as a counter cache column by
174
182
  # a has_many association on the model.
175
183
  def counter_cache_column?(model, column)
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record_doctor/detectors/base"
4
+
5
+ module ActiveRecordDoctor
6
+ module Detectors
7
+ class UnusedTables < 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 any Rails model and can be dropped"
20
+ end
21
+
22
+ def detect
23
+ each_table(except: config(:ignore_tables)) do |table|
24
+ next if models.any? { |model| model.table_name == table }
25
+
26
+ problem!(table: table)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordDoctor
4
- VERSION = "2.0.0"
4
+ VERSION = "2.1.0"
5
5
  end
@@ -22,6 +22,7 @@ require "active_record_doctor/detectors/short_primary_key_type"
22
22
  require "active_record_doctor/detectors/mismatched_foreign_key_type"
23
23
  require "active_record_doctor/detectors/table_without_primary_key"
24
24
  require "active_record_doctor/detectors/table_without_timestamps"
25
+ require "active_record_doctor/detectors/unused_tables"
25
26
  require "active_record_doctor/errors"
26
27
  require "active_record_doctor/help"
27
28
  require "active_record_doctor/runner"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_doctor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Navis
@@ -23,20 +23,48 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: 7.0.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: minitest
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '5.0'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: minitest-fork_executor
28
42
  requirement: !ruby/object:Gem::Requirement
29
43
  requirements:
30
44
  - - "~>"
31
45
  - !ruby/object:Gem::Version
32
- version: 1.0.2
46
+ version: '1.1'
33
47
  type: :development
34
48
  prerelease: false
35
49
  version_requirements: !ruby/object:Gem::Requirement
36
50
  requirements:
37
51
  - - "~>"
38
52
  - !ruby/object:Gem::Version
39
- version: 1.0.2
53
+ version: '1.1'
54
+ - !ruby/object:Gem::Dependency
55
+ name: minitest-mock
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '5.27'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '5.27'
40
68
  - !ruby/object:Gem::Dependency
41
69
  name: mysql2
42
70
  requirement: !ruby/object:Gem::Requirement
@@ -111,16 +139,16 @@ dependencies:
111
139
  name: sqlite3
112
140
  requirement: !ruby/object:Gem::Requirement
113
141
  requirements:
114
- - - "~>"
142
+ - - ">="
115
143
  - !ruby/object:Gem::Version
116
- version: 2.2.0
144
+ version: '1.4'
117
145
  type: :development
118
146
  prerelease: false
119
147
  version_requirements: !ruby/object:Gem::Requirement
120
148
  requirements:
121
- - - "~>"
149
+ - - ">="
122
150
  - !ruby/object:Gem::Version
123
- version: 2.2.0
151
+ version: '1.4'
124
152
  - !ruby/object:Gem::Dependency
125
153
  name: transient_record
126
154
  requirement: !ruby/object:Gem::Requirement
@@ -144,9 +172,6 @@ files:
144
172
  - MIT-LICENSE.txt
145
173
  - README.md
146
174
  - lib/active_record_doctor.rb
147
- - lib/active_record_doctor/adapters/database.rb
148
- - lib/active_record_doctor/adapters/table.rb
149
- - lib/active_record_doctor/adapters/validators.rb
150
175
  - lib/active_record_doctor/config.rb
151
176
  - lib/active_record_doctor/config/default.rb
152
177
  - lib/active_record_doctor/config/loader.rb
@@ -167,6 +192,7 @@ files:
167
192
  - lib/active_record_doctor/detectors/undefined_table_references.rb
168
193
  - lib/active_record_doctor/detectors/unindexed_deleted_at.rb
169
194
  - lib/active_record_doctor/detectors/unindexed_foreign_keys.rb
195
+ - lib/active_record_doctor/detectors/unused_tables.rb
170
196
  - lib/active_record_doctor/errors.rb
171
197
  - lib/active_record_doctor/help.rb
172
198
  - lib/active_record_doctor/logger.rb
@@ -200,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
226
  - !ruby/object:Gem::Version
201
227
  version: '0'
202
228
  requirements: []
203
- rubygems_version: 3.6.7
229
+ rubygems_version: 4.0.20
204
230
  specification_version: 4
205
231
  summary: Identify database issues before they hit production.
206
232
  test_files: []
@@ -1,17 +0,0 @@
1
- module ActiveRecordDoctor
2
- module Adapters
3
- class Database
4
- def initialize(connection)
5
- @connection = connection
6
- end
7
-
8
- def tables
9
- connection.tables
10
- end
11
-
12
- private
13
-
14
- attr_reader :connection
15
- end
16
- end
17
- end
@@ -1,18 +0,0 @@
1
- module ActiveRecordDoctor
2
- module Adapters
3
- class Table
4
- def initialize(connection, table_name)
5
- @connection = connection
6
- @table_name = table_name
7
- end
8
-
9
- def columns
10
- connection.columns(table_name)
11
- end
12
-
13
- private
14
-
15
- attr_reader :connection, :table_name
16
- end
17
- end
18
- end
@@ -1,16 +0,0 @@
1
- module ActiveRecordDoctor
2
- module Adapters
3
- class Validators
4
- def initialize(model_class, kind: :any)
5
- @model_class = model_class
6
- end
7
-
8
- def each
9
- end
10
-
11
- private
12
-
13
- attr_reader :model_class
14
- end
15
- end
16
- end