Sha256: 82742f15bdd7bf35e3bc3dcc7692dc53170aba300de4bf114a33f7ba6c58d440

Contents?: true

Size: 1.86 KB

Versions: 3

Compression:

Stored size: 1.86 KB

Contents

# frozen_string_literal: true

require "active_record_doctor/detectors/base"

module ActiveRecordDoctor
  module Detectors
    class MissingForeignKeys < Base # :nodoc:
      @description = "detect foreign-key-like columns lacking an actual foreign key constraint"
      @config = {
        ignore_tables: {
          description: "tables whose columns should not be checked",
          global: true
        },
        ignore_columns: {
          description: "columns, written as table.column, that should not be checked"
        }
      }

      private

      def message(table:, column:)
        "create a foreign key on #{table}.#{column} - looks like an association without a foreign key constraint"
      end

      def detect
        tables(except: config(:ignore_tables)).each do |table|
          connection.columns(table).each do |column|
            next if config(:ignore_columns).include?("#{table}.#{column.name}")

            # We need to skip polymorphic associations as they can reference
            # multiple tables but a foreign key constraint can reference
            # a single predefined table.
            next unless named_like_foreign_key?(column)
            next if foreign_key?(table, column)
            next if polymorphic_foreign_key?(table, column)

            problem!(table: table, column: column.name)
          end
        end
      end

      def named_like_foreign_key?(column)
        column.name.end_with?("_id")
      end

      def foreign_key?(table, column)
        connection.foreign_keys(table).any? do |foreign_key|
          foreign_key.options[:column] == column.name
        end
      end

      def polymorphic_foreign_key?(table, column)
        type_column_name = column.name.sub(/_id\Z/, "_type")
        connection.columns(table).any? do |another_column|
          another_column.name == type_column_name
        end
      end
    end
  end
end

Version data entries

3 entries across 3 versions & 1 rubygems

Version Path
active_record_doctor-1.10.0 lib/active_record_doctor/detectors/missing_foreign_keys.rb
active_record_doctor-1.9.0 lib/active_record_doctor/detectors/missing_foreign_keys.rb
active_record_doctor-1.9.0.rc1 lib/active_record_doctor/detectors/missing_foreign_keys.rb