Как изящно обрабатывать "Mysql2:: Ошибка: неверная дата" в ActiveRecord?

Я создаю приложение Rails 3.2 на устаревшей базе данных, в которой также есть неработающие записи в разных таблицах. Одной из проблем, вызывающих наибольшую головную боль, является то, что она содержит недопустимые даты.

Я установил песочницу, которую я однажды исправил вручную, чтобы заставить мой код работать. Теперь пришло время для развертывания. По этой причине песочница сбрасывается каждую ночь и копируется из действующей базы данных, индексы хорька перестраиваются и миграции применяются повторно. Мы будем часто развертывать в песочнице, чтобы получить последние исправления перед развертыванием в оперативной установке.

Поскольку унаследованное приложение PHP и это новое приложение Rails должны работать параллельно от нескольких недель до месяцев, мы не можем просто одноразово фиксировать даты (Обновление: просто для пояснения, это означает, что они работают в одной базе данных одновременно время). Мне нужен способ автоматизировать это, может быть, с помощью задачи миграции или рейка (я бы выбрал последнее).

Но проблема в том, что ActiveRecord блокирует загрузку таких записей, поэтому у меня нет возможности исследовать запись и фиксировать даты с помощью некоторых жестко запрограммированных предположений, сделанных в коде ruby.

Вторая проблема заключается в том, что у устаревшей базы данных есть несоответствия, потому что код PHP не использует транзакции, а некоторые пути к коду нарушены и оставляют сиротами и нарушают ограничения таблицы. Я буду иметь дело с этим, поскольку они происходят, о большинстве из них уже заботятся в моделях. Первая проблема связана с датами.

Как бы вы обычно это исправляли? Может быть, есть даже какой-то волшебный камень, который поддерживает миграцию устаревших баз данных с испорченными записями, перехватывая исключения и выполняя некоторый код попытки исправить...

Путь миграции использует MySQL и три производственные среды (стабильные с работающей базой данных, промежуточные с одной и той же базой данных и песочница с клоном базы данных, сбрасываемым каждую ночь). Мы решили не делать одноразовое отображение / миграцию данных, потому что мы не можем заменить полностью унаследованное приложение за один шаг (оно состоит из CMS с около 50000 статей, сотен тем, огромной файловой базы данных с изображениями и загрузками, поддерживает около 10 веб-сайтов около 12 лет работы и данных, грязный PHP-код с различными навыками программирования, дублированный код с разных этапов миграции, извлечение RSS-контента с партнерских сайтов для смешивания статей / постов оттуда в хронологию статей в темах нашего собственного приложения и много чего интересного...

Первым шагом является миграция внутреннего приложения для получения согласованного интерфейса администратора и публикации. Устаревшие веб-приложения по-прежнему должны записывать в базу данных (комментарии и другой контент, создаваемый посетителями). Таким образом, процесс исправления базы данных должен запускаться без присмотра на регулярной основе.

У нас уже есть исправления, которые изящно обрабатывают неработающие зависимости моделей в принадлежащих_вместе и has_many. Интеграция Paperclip была разработана для работы со всеми изобретенными фантастическими сопоставлениями имен файлов. И жемчужина airbrake сообщает обо всех сбоях приложений в нашу установку Redmine, поэтому мы получаем краткий обзор всех оставшихся ошибок.

Устаревшие приложения уже были модифицированы для работы с последней версией MySQL и были перенесены на текущий сервер базы данных MySQL.

4 ответа

У меня такая же проблема. Решением было сказать mysql2 не выполнять приведение, например так:

client.query(sql, cast: false).each do |row|
  row['some_date'] = Date.parse(row['some_date']) rescue(nil)
end

Посмотрите документацию mysql2 для деталей о том, как построить клиентский объект. Если требуется, обратитесь к rails db config через ActiveRecord::Base.configurations,

Похоже на: Rails: Как обработать существующие недопустимые даты в базе данных? а также без правильного ответа, поэтому я публикую свое решение ниже.

Я думаю, что самое простое решение, которое сработало для меня, это установить в файле database.yml запись cast: false, например, для раздела разработки

development
  <<: *default
  adapter: mysql2    
  (... some other settings ...)
  cast: false

Создайте задачу rake для импорта данных, которая выполняет все необходимые преобразования и исправления (включая анализ и исправление данных), и запускайте ее каждый раз, когда вы получаете свежее обновление из устаревшего приложения. Задача может использовать сырой SQL (методы поиска "execute" и "exec_query"), она не должна работать с моделями. Это будет ваш волшебный "драгоценный камень", который вы искали. Очевидно, что для этого не может быть универсального инструмента, поскольку каждый случай испорченных данных уникален. Но только не создавайте клуджи в своей новой кодовой базе.

Я верю, что это решит вашу проблему Date.parse()

например, Date.parse(foo.created_at)

Другие вопросы по тегам