You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7.2升级后Duration与PostgreSQL Interval类型异常排查

Rails 7.2升级后before_save设置的PostgreSQL Interval字段save后内存对象值为nil的解决办法

问题核心

升级Rails到7.2后,通过before_save回调设置的interval类型字段(如duration),在save!执行后内存对象中该字段为nil,但数据库已正确插入值,仅在reload后能获取到正确值。这与Rails 7.2移除的「deprecated support to quote ActiveSupport::Duration」变更直接相关。

简便解决办法

方法1:在回调中手动序列化Duration对象

修改Event模型的set_duration方法,将ActiveSupport::Duration对象序列化为PostgreSQL可识别的格式,确保内存对象保留正确值:

class Event < ApplicationRecord
  before_save :set_duration
  before_save :update_classification

  def set_duration
    duration_value = end_datetime - start_datetime
    # 用ActiveRecord的Interval类型序列化Duration
    self.duration = ActiveRecord::Type::Interval.new.serialize(duration_value)
  end

  def update_classification
    if duration >= 4.hours 
      self.classification = "long"
    else
      self.classification = "short"
    end
  end
end

方法2:覆盖字段赋值方法(全局生效)

如果多个模型都有类似场景,可在模型中覆盖duration=方法,统一处理Duration对象的序列化:

class Event < ApplicationRecord
  before_save :set_duration
  before_save :update_classification

  def duration=(value)
    if value.is_a?(ActiveSupport::Duration)
      super(ActiveRecord::Type::Interval.new.serialize(value))
    else
      super
    end
  end

  def set_duration
    self.duration = end_datetime - start_datetime
  end

  def update_classification
    if duration >= 4.hours 
      self.classification = "long"
    else
      self.classification = "short"
    end
  end
end

原理说明

Rails 7.2移除了对ActiveSupport::Duration的自动引用支持,此前版本会自动将Duration对象转换为PostgreSQL Interval格式并在内存模型中保留该值;现在直接赋值Duration对象时,虽然数据库插入逻辑仍能正常序列化,但内存模型不会再维护该字段的状态,导致save!后属性为nil。通过手动序列化,我们让内存对象存储的是数据库兼容的格式,ActiveRecord会正确维护其状态,无需reload即可访问。

内容的提问来源于stack exchange,提问作者NGobin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:47:32