Class: RuboCop::Cop::Neeto::UnsafeColumnDeletion

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/neeto/unsafe_column_deletion.rb

Overview

‘remove_column` is considered as a dangerous operation. If not used correctly, it could cause irreversible data loss. It is advised to rename the column to `column_name_deprecated_on_yyyy_mm_dd` instead. The renamed column can be safely dropped in a later migration. The cop permits dropping columns that are named in the above format.

Examples:

UnsafeColumnDeletion: true (default)

# Enforces the usage of `rename_column` over `remove_column`.

# bad
remove_column :users, :email

# bad
change_table :users do |t|
  t.remove :email
end

# good
remove_column :users, :email_deprecated_on_2024_08_09

# good
drop_table :users do |t|
  t.remove :email_deprecated_on_2024_08_09
end

Constant Summary collapse

SAFE_COLUMN_NAME_REGEX =
/\w+_deprecated_on_\d{4}_\d{2}_\d{2}/
CURRENT_DATE =
DateTime.now.strftime("%Y_%m_%d")
MSG_REMOVE_COLUMN =
"'remove_column' is a dangerous operation. If " \
"not used correctly, it could cause irreversible data loss. You must perform " \
"'rename_column :%{table_name}, %{column_name}, :%{column_name}_deprecated_on_#{CURRENT_DATE}' " \
"instead. The renamed column can be safely dropped in a future migration."
MSG_CHANGE_TABLE =
"'t.remove' is a dangerous operation. If not used correctly, " \
"it could cause irreversible data loss. You must perform " \
"'t.rename :%{column_name}, :%{column_name}_deprecated_on_#{CURRENT_DATE}' " \
"instead. The renamed column can be safely dropped in a future migration."
RESTRICT_ON_SEND =
%i[remove_column change_table].freeze

Instance Method Summary collapse

Instance Method Details

#on_block(node) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/rubocop/cop/neeto/unsafe_column_deletion.rb', line 67

def on_block(node)
  return unless unsafe_remove_column_change_table?(node)

  node.each_descendant(:send) do |send_node|
    next unless send_node.method_name == :remove

    column_name = send_node.arguments.first.value
    message = format(MSG_CHANGE_TABLE, column_name:)
    add_offense(send_node, message:) unless SAFE_COLUMN_NAME_REGEX.match?(column_name)
  end
end

#on_send(node) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/rubocop/cop/neeto/unsafe_column_deletion.rb', line 58

def on_send(node)
  return unless unsafe_remove_column?(node)

  unsafe_remove_column?(node) do |table_name, column_name|
    message = format(MSG_REMOVE_COLUMN, table_name:, column_name:)
    add_offense(node, message:) unless SAFE_COLUMN_NAME_REGEX.match?(column_name)
  end
end