diff --git a/README.md b/README.md index 29f0f65..a98573f 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ can detect: * primary keys having short integer types - [`active_record_doctor:short_primary_key_type`](#detecting-primary-keys-having-short-integer-types) * mismatched foreign key types - [`active_record_doctor:mismatched_foreign_key_type`](#detecting-mismatched-foreign-key-types) * tables without primary keys - [`active_record_doctor:table_without_primary_key`](#detecting-tables-without-primary-keys) +* tables without timestamps - [`active_record_doctor:table_without_timestamps`](#detecting-tables-without-timestamps) It can also: @@ -642,6 +643,29 @@ Supported configuration options: - `enabled` - set to `false` to disable the detector altogether - `ignore_tables` - tables whose primary key existence should not be checked +### Detecting Tables Without Timestamps + +Tables should have timestamp columns (`created_at`/`updated_at`). Otherwise, it becomes problematic +to easily find when the record was created/updated, if the table is active or can be removed, +automatic Rails cache expiration after record updates is not possible. + +Running the command below will list all tables without default timestamp columns: + +``` +bundle exec rake active_record_doctor:table_without_timestamps +``` + +The output of the command looks like this: + +``` +add a created_at column to companies +``` + +Supported configuration options: + +- `enabled` - set to `false` to disable the detector altogether +- `ignore_tables` - tables whose timestamp columns existence should not be checked + ## Ruby and Rails Compatibility Policy The goal of the policy is to ensure proper functioning in reasonable diff --git a/lib/active_record_doctor.rb b/lib/active_record_doctor.rb index 6659a4a..8a7b4b2 100644 --- a/lib/active_record_doctor.rb +++ b/lib/active_record_doctor.rb @@ -21,6 +21,7 @@ require "active_record_doctor/detectors/short_primary_key_type" require "active_record_doctor/detectors/mismatched_foreign_key_type" require "active_record_doctor/detectors/table_without_primary_key" +require "active_record_doctor/detectors/table_without_timestamps" require "active_record_doctor/errors" require "active_record_doctor/help" require "active_record_doctor/runner" diff --git a/lib/active_record_doctor/config/default.rb b/lib/active_record_doctor/config/default.rb index d37bcaf..0d30098 100644 --- a/lib/active_record_doctor/config/default.rb +++ b/lib/active_record_doctor/config/default.rb @@ -64,6 +64,10 @@ enabled: true, ignore_tables: [] + detector :table_without_timestamps, + enabled: true, + ignore_tables: [] + detector :undefined_table_references, enabled: true, ignore_models: [] diff --git a/lib/active_record_doctor/detectors/table_without_timestamps.rb b/lib/active_record_doctor/detectors/table_without_timestamps.rb new file mode 100644 index 0000000..98b744f --- /dev/null +++ b/lib/active_record_doctor/detectors/table_without_timestamps.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require "active_record_doctor/detectors/base" + +module ActiveRecordDoctor + module Detectors + class TableWithoutTimestamps < Base # :nodoc: + @description = "detect tables without created_at/updated_at columns" + @config = { + ignore_tables: { + description: "tables whose timestamp columns existence should not be checked", + global: true + } + } + + private + + TIMESTAMPS = { + "created_at" => "created_on", + "updated_at" => "updated_on" + }.freeze + + def message(table:, column:) + "add a #{column} column to #{table}" + end + + def detect + each_table(except: config(:ignore_tables)) do |table| + TIMESTAMPS.each do |column, alternative_column| + unless column(table, column) || column(table, alternative_column) + problem!(table: table, column: column) + end + end + end + end + end + end +end diff --git a/test/active_record_doctor/detectors/table_without_timestamps_test.rb b/test/active_record_doctor/detectors/table_without_timestamps_test.rb new file mode 100644 index 0000000..d0f6f6a --- /dev/null +++ b/test/active_record_doctor/detectors/table_without_timestamps_test.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +class ActiveRecordDoctor::Detectors::TableWithoutTimestampsTest < Minitest::Test + def test_table_without_timestamps_reported + Context.create_table(:companies) do |t| + t.string :name + end + + assert_problems(<<~OUTPUT) + add a created_at column to companies + add a updated_at column to companies + OUTPUT + end + + def test_table_with_timestamps_is_not_reported + Context.create_table(:companies) do |t| + t.timestamps + end + refute_problems + end + + def test_table_with_alternative_timestamps_is_not_reported + Context.create_table(:companies) do |t| + t.timestamp :created_on + t.timestamp :updated_on + end + refute_problems + end + + def test_config_ignore_tables + Context.create_table(:companies) + + config_file(<<-CONFIG) + ActiveRecordDoctor.configure do |config| + config.detector :table_without_timestamps, + ignore_tables: ["companies"] + end + CONFIG + + refute_problems + end + + def test_global_ignore_tables + Context.create_table(:companies) + + config_file(<<-CONFIG) + ActiveRecordDoctor.configure do |config| + config.global :ignore_tables, ["companies"] + end + CONFIG + + refute_problems + end +end