【问题标题】:Rails: How to handle existing invalid dates in database?Rails:如何处理数据库中现有的无效日期?
【发布时间】:2013-08-01 16:51:11
【问题描述】:

首先,这与我的另一个问题直接相关: How to gracefully handle "Mysql2::Error: Invalid date" in ActiveRecord?

但我仍然不想跳过所有编写迁移来确定日期的循环。这不会是最后一个日期无效的表格,我需要一些更通用的方法。

所以我们开始吧:

我正在使用包含无效日期的旧版 MySQL 数据库,有时像 2010-01-00 或 0000-04-25...Rails 不会加载此类记录(旧版本的 Rails 会加载)。

我不想(也不能)手动或自动更正这些日期。应该由这些记录的作者来更正这些日期。旧系统是一个允许此类烦恼的 PHP 应用程序。 Rails 应用程序应该/将阻止用户在日期有效之前保存记录。

问题似乎不在于 Rails 本身,而在于 Rails mysql gem 的 .so 库更深层次。

所以我的问题不是关于如何验证日期或如何插入无效日期。我不想那样做,这在 stackoverflow 和互联网的其余部分都有很多答案。我的问题是如何从 MySQL 中读取已经存在于数据库中的无效日期,而不会使 Rails 爆炸成 1000 个小块......

列类型是DATETIME,我不确定转换为字符串是否有帮助,因为 Rails 在任何与 ActiveRecord 相关的解析开始之前就会阻塞。

这是确切的错误和回溯:

$导轨c 加载开发环境(Rails 3.2.13) irb(main):001:0> Poll.first 轮询负载 (0.5ms) SELECT `polls`.* FROM `polls` LIMIT 1 Mysql2::Error:无效日期: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 中的任何输出例程,因此不应该被解析。因此,在类型转换之前使用值的建议将无济于事。

【问题讨论】:

  • 你能把值转换成字符串吗?
  • 什么是列类型?
  • @ChrisHeald 将列类型添加到我的问题中:DATETIME

标签: mysql ruby-on-rails date activerecord ruby-on-rails-3.2


【解决方案1】:

我认为对我有用的最简单的解决方案是在 database.yml 文件中设置 cast: false,例如开发部分

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

【讨论】:

  • 这听起来很有趣...我会跟进的。
【解决方案2】:

试试这个

ActiveRecord::AttributeMethods::BeforeTypeCast 提供了一种在类型转换和反序列化之前读取属性值的方法。

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

【讨论】:

  • 那行不通,因为代码永远不会到达那个点。从超出 ActiveRecords 范围的 mysql gem 中抛出了一个无效的日期异常......我已经尝试过只是为了意识到错误是在 mysql gem 的 C 代码中的某处生成的。
  • 我认为您需要找到一种方法让 ActiveRecord 告诉 mySql 将日期转换为 查询 中的字符串。即SELECT DATE_FORMAT(YourCol, '%c-%e-%Y')
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-07
  • 2014-05-20
  • 2011-07-05
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多