Rails: Как обработать существующие недопустимые даты в базе данных?

Во-первых, это напрямую связано с моим другим вопросом: как изящно обрабатывать "Mysql2::Error: Invalid date" в ActiveRecord?

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

Итак, поехали:

Я использую устаревшую базу данных MySQL, которая содержит недопустимые даты, иногда как 2010-01-00 или 0000-04-25... Rails не загружает такие записи (старые версии Rails делали).

Я не хочу (и не могу) исправить эти даты вручную или автоматически. Авторы этих записей должны исправить эти даты. Старая система была приложением PHP, которое допускало такие неприятности. Приложение Rails должно / будет просто запрещать пользователю сохранять запись до тех пор, пока даты не станут действительными.

Проблема, похоже, не в самих Rails, а в глубине библиотеки.so библиотеки rails mysql.

Поэтому мой вопрос не о том, как проверить дату или как вставить недействительные даты. Я не хочу этого делать, и это покрыто многочисленными ответами по всему стеку и всему Интернету. Мой вопрос заключается в том, как ПРОЧИТАТЬ недействительные даты из MySQL, которые уже существуют в базе данных, без Rails, взрывающегося на 1000 маленьких кусочков...

Тип столбца DATETIME и я не уверен, что приведение к строке могло бы помочь, потому что Rails задыхается до того, как какой-либо связанный с ActiveRecord стартует.

Вот точная ошибка и обратный след:

$ рельсы с
Загрузка среды разработки (Rails 3.2.13)
irb(основной):001:0> Poll.first
  Загрузка опроса (0,5 мс) ВЫБЕРИТЕ `polls`.* ИЗ` `опросов` LIMIT 1
Mysql2:: Ошибка: неверная дата: 2003-00-01 00:00:00
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/connection_adapters/mysql2_adapter.rb:216:in `each'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/connection_adapters/mysql2_adapter.rb:216:in `to_a'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/connection_adapters/mysql2_adapter.rb:216:in `exec_query'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/connection_adapters/mysql2_adapter.rb:224:in `select'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/querying.rb:38:in `find_by_sql'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/explain.rb:41:in `logging_query_plan'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/querying.rb:37:in `find_by_sql'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/relation.rb:171:in `exec_queries'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/relation.rb:160:in `to_a'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/explain.rb:34:in `logging_query_plan'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/relation.rb:159:in `to_a'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:380:in `find_first'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:122:in `first'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/querying.rb:5:in `__send__'
        из /home/kakra/.gem/ruby/1.8/gems/activerecord-3.2.13/lib/active_record/querying.rb:5:in `first'
        из (irb):1

Обратный след остается прежним, даже когда я Poll.first.title поэтому некоторая дата никогда не должна достигать какой-либо процедуры вывода в IRB и, следовательно, никогда не должна анализироваться. Так что предложения по использованию значения перед приведением типов не помогут.

2 ответа

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

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

Попробуй это

ActiveRecord::AttributeMethods::BeforeTypeCast предоставляет способ прочитать значение атрибутов перед приведением типов и десериализацией.

http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/BeforeTypeCast.html

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