Class: RuboCop::Cop::DevDoc::Migration::AvoidConditionalSchemaChanges
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Migration::AvoidConditionalSchemaChanges
- Defined in:
- lib/rubocop/cop/dev_doc/migration/avoid_conditional_schema_changes.rb
Overview
Flag conditional schema-change helpers (‘add_column_if_not_exists`, `column_exists?`, etc.) inside migration files.
## Rationale Migrations are deterministic state transitions: “DB was at state N; after this migration it is at state N+1.” Conditional schema helpers imply “I don’t know what state the DB is in,” which contradicts the migration model and hides schema drift.
If a column “might already exist,” that is a symptom — investigate why before papering over it with a defensive guard.
The escape hatch is a per-line ‘rubocop:disable` comment with a rationale explaining the known-drift repair.
❌ hides drift; state is unknown
add_column_if_not_exists :users, :something, :string
add_column :users, :bar, :string unless column_exists?(:users, :bar)
✔️ declarative state transition
add_column :users, :something, :string
✔️ documented one-shot drift repair (escape hatch)
# rubocop:disable DevDoc/Migration/AvoidConditionalSchemaChanges
add_column_if_not_exists :users, :something, :string
# rubocop:enable DevDoc/Migration/AvoidConditionalSchemaChanges
Constant Summary collapse
- IF_NOT_EXISTS_METHODS =
%i[ add_column_if_not_exists add_index_if_not_exists add_foreign_key_if_not_exists add_reference_if_not_exists remove_column_if_exists remove_index_if_exists remove_foreign_key_if_exists remove_reference_if_exists ].freeze
- EXISTENCE_PREDICATES =
%i[ column_exists? table_exists? index_exists? foreign_key_exists? ].freeze
- MSG_IF_NOT_EXISTS =
'`%<method>s` hides schema drift. Use the non-conditional form and investigate ' \ 'why states diverge. Suppress with a `rubocop:disable` comment only for documented ' \ 'one-shot drift repairs.'.freeze
- MSG_PREDICATE =
'`%<method>s` guard hides schema drift. Use unconditional schema operations and ' \ 'investigate why states diverge. Suppress with a `rubocop:disable` comment only for ' \ 'documented one-shot drift repairs.'.freeze
Instance Method Summary collapse
Instance Method Details
#on_send(node) ⇒ Object
76 77 78 79 80 81 82 83 84 |
# File 'lib/rubocop/cop/dev_doc/migration/avoid_conditional_schema_changes.rb', line 76 def on_send(node) if IF_NOT_EXISTS_METHODS.include?(node.method_name) add_offense(node.loc.selector, message: format(MSG_IF_NOT_EXISTS, method: node.method_name)) elsif EXISTENCE_PREDICATES.include?(node.method_name) add_offense(node.loc.selector, message: format(MSG_PREDICATE, method: node.method_name)) end end |