Ruby on Rails迁移报错:如何基于另一字段更新日期字段并加1天?
搞定Order表Workdate字段更新的迁移报错问题
嘿,你的迁移代码报错是因为用错了update_all的写法——update_all是直接生成SQL交给数据库执行的,不能在里面用Ruby层面的1.day方法,也不能直接写internal_delivery_date(这在Ruby里会被当成未定义的变量,数据库也不认Ruby的属性名写法)。
下面分情况给你正确的实现方式:
针对MySQL/MariaDB的写法
MySQL用DATE_ADD函数来做日期加法,把迁移改成这样:
class UpdateWorkdate < ActiveRecord::Migration[5.0] def self.up Order.update_all("workdate = DATE_ADD(internal_delivery_date, INTERVAL 1 DAY)") end def self.down # 可选:添加回滚逻辑,比如把workdate重置为原来的值 # Order.update_all("workdate = NULL") end end
针对PostgreSQL的写法
PostgreSQL支持直接给日期加间隔,代码如下:
class UpdateWorkdate < ActiveRecord::Migration[5.0] def self.up Order.update_all("workdate = internal_delivery_date + INTERVAL '1 day'") end def self.down # 按需添加回滚逻辑 end end
跨数据库兼容的通用写法
如果你的项目可能切换数据库,用ActiveRecord的Arel来生成兼容SQL是最好的选择,它会自动适配不同数据库的语法:
class UpdateWorkdate < ActiveRecord::Migration[5.0] def self.up order_table = Order.arel_table update_rule = order_table[:workdate].eq(order_table[:internal_delivery_date] + 1.day) Order.update_all(update_rule) end def self.down # 可选回滚逻辑 end end
为啥原来的代码会报错?
再给你拆解下问题点:
internal_delivery_date在你的代码里是Ruby变量,但你没定义它,所以Ruby会直接抛出未定义变量的错误;- 就算你解决了变量问题,
1.day是ActiveSupport的Ruby方法,生成的是Ruby对象,数据库根本不认识这个类型,还是会报错。
所以必须用数据库能理解的SQL语法,或者用Arel帮你转成正确的SQL。
内容的提问来源于stack exchange,提问作者F. LK
相关产品推荐
相关产品推荐

