Что такое ignored_columns
ignored_columns — это макрос (class method) в ActiveRecord::Base, который позволяет указать модели Rails, какие колонки из соответствующей таблицы в базе данных следует полностью игнорировать.
Когда Rails загружает модель, он обращается к базе данных, чтобы получить схему таблицы и понять, какие у нее есть колонки. На основе этого списка он создает для каждого экземпляра модели соответствующие атрибуты (геттеры и сеттеры).
Если вы добавляете колонку в ignored_columns, Rails будет вести себя так, будто этой колонки в базе данных не существует.
- Он не будет создавать для нее атрибуты в модели.
- Он не будет пытаться читать из нее данные при
SELECTзапросах. - Он не будет пытаться записать в нее данные при
INSERTилиUPDATE.
Зачем это нужно? Проблема нулевого простоя (Zero-Downtime Deployment)
Основное предназначение ignored_columns — обеспечение безопасных миграций по удалению колонок из базы данных в продакшн-среде без остановки приложения.
Представьте себе типичный процесс развертывания:
- Выкатывается новый код.
- Запускаются миграции базы данных.
Теперь рассмотрим, что произойдет, если вы просто удалите колонку без ignored_columns:
Сценарий сбоя:
- Деплой кода: Вы удалили использование колонки
users.legacy_dataиз всего кода и выкатили этот код на продакшн-серверы. - Состояние до миграции: Новый код уже работает, но миграция на удаление колонки
legacy_dataеще не запущена. Колонна все еще существует в БД. - Кэш Rails: Когда сервер с новым кодом запускается, Rails смотрит на схему таблицы
usersи видит колонкуlegacy_data. Он кэширует эту информацию и создает для моделиUserсоответствующий атрибут. - Запуск миграции: Вы запускаете миграцию
remove_column :users, :legacy_data. База данных удаляет колонку. - КРАХ! Следующий запрос, который приходит на ваш сервер (который все еще работает со старым кэшем схемы), пытается выполнить что-то вроде
User.find(1). ActiveRecord генерирует SQLSELECT "users".* FROM "users" WHERE "users"."id" = 1. База данных пытается выполнить этот запрос, но не находит колонкуlegacy_dataи возвращает ошибкуActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column "legacy_data" does not exist. - Результат: Ваше приложение падает с ошибкой 500 до тех пор, пока все серверные процессы не будут перезапущены, чтобы они обновили свой кэш схемы уже без удаленной колонки. Это и есть простой (downtime).
Как ignored_columns решает эту проблему
ignored_columns позволяет разорвать этот порочный круг, разделив процесс на три безопасных шага.
Шаг 1: Деплой с игнорированием колонки
Сначала вы готовите код к тому, что колонка скоро исчезнет.
-
Не удаляйте колонку! Просто зайдите в модель и добавьте
ignored_columns.# app/models/user.rb
class User < ApplicationRecord
# ...
self.ignored_columns = [:legacy_data]
# ...
end -
Создайте Pull Request и выкатите этот код в продакшн.
Что теперь происходит? Все ваши серверы теперь работают с кодом, который полностью игнорирует колонку legacy_data. Даже если она есть в базе, Rails ее не видит, не читает и не пишет в нее. Приложение полностью готово к ее физическому удалению.
Шаг 2: Деплой с миграцией на удаление
Теперь, когда код готов, можно безопасно удалять колонку.
-
Создайте миграцию.
rails g migration RemoveLegacyDataFromUsers -
Добавьте в нее код удаления колонки.
# db/migrate/20250825140000_remove_legacy_data_from_users.rb
class RemoveLegacyDataFromUsers < ActiveRecord::Migration[7.1]
def change
remove_column :users, :legacy_data, :string
end
end -
Создайте Pull Request и выкатите его, запустив миграцию.
Что теперь происходит? Миграция выполняется и удаляет колонку из базы данных. Ваши серверы, которые уже работают с кодом из Шага 1, даже не замечают этого, потому что они и так игнорировали эту колонку. Никаких ошибок, никакого простоя.
Шаг 3: Деплой с очисткой кода
Колонка удалена, но в коде остался "технический долг" — строка ignored_columns. Ее нужно убрать.
-
Удалите
ignored_columnsиз модели.# app/models/user.rb
class User < ApplicationRecord
# ...
# self.ignored_columns = [:legacy_data] # <- Убираем эту строку
# ...
end -
Создайте Pull Request и выкатите этот код.
Теперь ваш код и схема базы данных снова находятся в идеальной синхронизации.
Важные моменты и лучшие практики
-
Несколько колонок: Если нужно игнорировать несколько колонок, передайте массив символов:
self.ignored_columns = [:legacy_data, :old_preference, :temp_field] -
Безопасное добавление: Если в модели (или в одном из ее
concerns) уже может быть определенignored_columns, безопаснее добавлять к существующему списку, а не перезаписывать его:self.ignored_columns += [:new_column_to_ignore] -
Инструменты: Гем
strong_migrationsавтоматизирует проверку на подобные опасные миграции и не даст вам удалить колонку без предварительного игнорирования, что очень помогает в командной работе.
Итог: ignored_columns — это критически важный инструмент для управления схемой базы данных в работающем приложении. Он позволяет вам безопасно, в несколько этапов, удалять колонки, полностью исключая риск падения приложения и обеспечивая тот самый "zero-downtime".