Как изящно обрабатывать "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)