Комментарии 15
Подумаю, как Ваш способ органично добавить в статью!
class AddLastSmiledAtColumnToUsers < ActiveRecord::Migration[5.1]
def up
add_column :users, :last_smiled_at, :datetime
add_index :users, :last_smiled_at
connection.execute <<~SQL
update users u
set u.last_smiled_at =
(select max(s.created_at) from smiles s where s.user_id = u.id)
SQL
end
def down
remove_index :users, column: :last_smiled_at
remove_column :users, :last_smiled_at
end
end
Главное преимущество в том, что это никогда ничего не сломает, потому что SQL работает напрямую со структурой базы, которая была создана предыдущими миграциями, и это не зависит от Ruby-кода (когда классы меняются и пр.)
UPD: пардон, этот подход в статье есть, я был невнимателен :)
Действительно, я призываю отказываться от SQL в миграциях схемы для миграции данных, кроме случаев, когда без этого нельзя сделать откатываемую миграцию.
Главными причинами являются увеличение простоя при развертывании и нагрузка на читателя, даже если SQL совсем простой. Как правило, с SQL сталкиваться приходится редко в Ruby On Rails проектах.
1. создать колонку
2. SQL для заполнения значений в ней
3. добавить «not null» constraint
Раздел называется: Исключения, когда допустимо делать миграции данных в миграциях схемы.
А уж, если мы затаскиваем это в кодовую базу, то тут не далеко до желания покрыть эту логику тестом и даже, в процессе обнаружить ошибки, которые можно пропустить при отладке логики на стейджинге через REPL.
Благодаря этому размышлению я придумал опрос об используемых людьми решениях.
Кстати, я везде пользуюсь джемом annotate_models, чтобы прямо из модели видеть структуру соответствующей таблицы.
Мы тоже пользуемся annotate_models. Очень удобно.
В таком проекте подошёл бы подход с гемом для миграций данных в стиле миграций схемы. Либо можно продолжать использовать миграции схемы для миграций данных, если связанные с этим проблемы не сильно актуальны в силу масштаба.
И было бы здорово, если бы Вы поучаствовали в голосовании под статьёй.
Проходил через почти все. На каком-то этапе сбор тестового проекта начинает быть похожим на сборку-разборку-подпирание-перепланирование-сборку и т.д. дома. То есть очень долго, тяжело, много истории (кода, миграций), забытая логика, неотслеживаемые баги...
Одномоментные миграции запросами прямо в базу — заманчиво, очень заманчиво, но не в энтэрпрайзе.
Если приложение большое, то я выбираю подход "циклической эволюции". Миграции делаем только на мажорных версиях приложения. Минорные — без изменений в базе. Делаем микросервисы, где возможно, чтобы раздробить миграции несколькими базами. Когда история миграций доходит до критической отметки (можно научно определить, а можно субъективно), то пишем новую версию приложения/микросервиса (не допиливаем мажорную, а пишем с нуля), делаем миграцию в него и заново начинаем наращивать миграции.
Сложно? Разработчики довольны, что пишут новое, а не ковыряются в старом, архитектор пересматривает базовые решения (иначе не мог бы) в пользу оптимальных, старые языки/фреймворки и т.п. заменяются новыми, четкая и понятная бизнес-логика. Кто на поддержке наследия мамонтов работал, тот точно оценит.
Миграции данных в Ruby On Rails