You need to enable JavaScript to run this app. 含Postgres生成列的Rails迁移测试环境报错,为何开发/生产环境运行正常?
优惠活动
大模型
产品
解决方案
定价
更多

含Postgres生成列的Rails迁移测试环境报错,为何开发/生产环境运行正常?

不同环境迁移行为差异的根因

开发、生产环境正常执行的原因

  • 这类环境的数据库初始化流程为逐次、按版本执行所有迁移脚本。编写的原生SQL ALTER TABLE语句会被完整透传给Postgres,数据库会正确识别GENERATED ALWAYS AS (...) STORED是存储生成列的合法定义,完全符合语法规则,因此不会触发报错。
  • 流程中schema.rb仅作为迁移执行完成后的库结构导出文件存在,不会被反向用来搭建数据库,因此哪怕导出的结构定义有错误,也不会影响开发、生产环境的运行。

测试环境直接报错的核心原因

  • Rails测试环境默认的数据库初始化逻辑和其他环境完全不同:为了压缩测试准备时长,它不会逐次执行全部迁移,而是直接加载导出的schema结构来快速搭建测试库。
  • 当前Rails的PostgreSQL适配器存在能力缺陷:在导出存储生成列的定义到schema.rb时,无法正确识别GENERATED ALWAYS的语法属性,错误把生成列的计算表达式当成了普通列的DEFAULT值写入文件,最终生成的定义为:
    t.tsvector "agency_names_tsvector", default: -> { "to_tsvector('english'::regconfig, (COALESCE(agency_names, ''::character varying))::text)" }
    
  • 当测试环境基于这个错误的schema定义建表时,Postgres会直接收到带同表列引用的DEFAULT子句——普通列的DEFAULT值不允许引用其他同表列,这是Postgres的语法硬限制,因此直接抛出PG::FeatureNotSupported: ERROR: cannot use column reference in DEFAULT expression的错误。

统一配置修复的合理性

  • 全环境统一设置config.active_record.schema_format = :sql时,Rails会导出Postgres原生DDL格式的structure.sql,文件中会完整保留存储生成列的合法定义,不会出现把生成列错写为DEFAULT的问题,既解决了测试环境的报错,也不需要给不同环境配置做差异化调整。

注:这个问题和迁移脚本本身的写法无关,只要使用schema.rb的Ruby格式导出结构,遇到存储生成列的场景就会触发适配器的导出缺陷。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.08 14:54:03