Class: RuboCop::Cop::Migration::ChangeColumn

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/migration/change_column.rb

Overview

Avoid changing column type that is in use.

Changing the type of a column causes the entire table to be rewritten. During this time, reads and writes are blocked in Postgres, and writes are blocked in MySQL and MariaDB.

Some changes don’t require a table rewrite and are safe in PostgreSQL:

Type | Safe Changes — | — ‘cidr` | Changing to `inet` `citext` | Changing to `text` if not indexed, changing to `string` with no `:limit` if not indexed `datetime` | Increasing or removing `:precision`, changing to `timestamptz` when session time zone is UTC in Postgres 12+ `decimal` | Increasing `:precision` at same `:scale`, removing `:precision` and `:scale` `interval` | Increasing or removing `:precision` `numeric` | Increasing `:precision` at same `:scale`, removing `:precision` and `:scale` `string` | Increasing or removing `:limit`, changing to `text`, changing `citext` if not indexed `text` | Changing to `string` with no `:limit`, changing to `citext` if not indexed `time` | Increasing or removing `:precision` `timestamptz` | Increasing or removing `:limit`, changing to `datetime` when session time zone is UTC in Postgres 12+

And some in MySQL and MariaDB:

Type | Safe Changes — | — ‘string` | Increasing `:limit` from under 255 up to 255, increasing `:limit` from over 255 to the max

A safer approach is to:

  1. Create a new column

  2. Write to both columns

  3. Backfill data from the old column to the new column

  4. Move reads from the old column to the new column

  5. Stop writing to the old column

  6. Drop the old column

Examples:

# bad
class ChangeUsersSomeColumnType < ActiveRecord::Migration[7.0]
  def change
    change_column :users, :some_column, :new_type
  end
end

# good
class AddUsersAnotherColumn < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :another_column, :new_type
  end
end

class RemoveUsersSomeColumn < ActiveRecord::Migration[7.0]
  def change
    remove_column :users, :some_column
  end
end

Constant Summary collapse

MSG =
'Avoid changing column type that is in use.'
RESTRICT_ON_SEND =
%i[
  change
  change_column
].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ void

This method returns an undefined value.

Parameters:

  • node (RuboCop::AST::SendNode)


74
75
76
77
78
# File 'lib/rubocop/cop/migration/change_column.rb', line 74

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

  add_offense(node)
end