升级Rails7后,PG的timestamp with time zone返回Time而非ActiveSupport::TimeWithZone如何解决?
从Rails 6升级到Rails 7并执行bundle exec rails app:update后,原本映射PostgreSQL timestamp with time zone列的模型属性,突然返回Time对象而非ActiveSupport::TimeWithZone对象。
数据库结构示例(Structure.sql):
CREATE TABLE public.blogs ( id bigint NOT NULL, created_at timestamp with time zone, -- 其他字段... );
Rails 6时期的表现:
Blog.last.created_at.class #=> ActiveSupport::TimeWithZone
Rails 7时期的表现:
Blog.last.created_at.class #=> Time
如何让Rails将这些列识别为ActiveSupport::TimeWithZone类型?
以下是几种可行的修复方法:
检查并修正时区配置
确认config/application.rb或对应环境配置文件(config/environments/*.rb)中的时区相关配置是否正确:config.time_zone = 'Beijing' # 替换为你的业务时区 config.active_record.default_timezone = :utc config.active_record.time_zone_aware_attributes = true执行
app:update时部分配置可能被覆盖,需要重新确认并调整。在模型中显式声明属性类型
在目标模型里,直接指定字段的类型为:datetime,强制Rails将其映射为ActiveSupport::TimeWithZone:class Blog < ApplicationRecord attribute :created_at, :datetime attribute :updated_at, :datetime -- 其他需要处理的时区字段... end重定义PostgreSQL适配器的类型映射
在config/initializers/active_record.rb中添加配置,将PostgreSQL的timestamp with time zone类型关联到Rails的:datetime类型:ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:datetime] = { name: "timestamp with time zone" }此配置会全局生效,让所有
timestamp with time zone列都被识别为时区感知类型。排查升级生成的新配置
查看config/initializers/new_framework_defaults_7_0.rb等升级新增的配置文件,确认是否有影响时区类型处理的配置,比如config.active_record.datetime_without_timezone_type,若该配置被设置为:time可能导致异常,建议注释或调整:# 避免此配置覆盖时区类型处理 # config.active_record.datetime_without_timezone_type = :time
内容的提问来源于stack exchange,提问作者steel

