Upsert gem适配PostgreSQL 15报错:d.adsrc列不存在的解决咨询
适配PostgreSQL 15的Upsert解决方案(不用升级Rails 6)
以下是几个可行的方案,按推荐优先级排序:
1. 手动修补Upsert gem源码
问题根源是Upsert在获取列默认值时用了PostgreSQL 12+已废弃的adsrc列,PostgreSQL现在用pg_get_expr(d.adbin, d.adrelid)来获取默认值表达式。你可以直接修改本地gem文件:
- 用
bundle show upsert找到gem的安装路径 - 打开
lib/upsert/postgresql/column_definition.rb - 找到查询默认值的代码段,把
d.adsrc替换成pg_get_expr(d.adbin, d.adrelid),比如把查询语句里的SELECT d.adsrc改成SELECT pg_get_expr(d.adbin, d.adrelid) AS adsrc,这样后续代码还能沿用原来的adsrc键取值 - 修改完成后重启应用测试即可
2. 使用社区适配过的fork版Upsert
GitHub上有官方维护者针对PostgreSQL 12+修复了该问题的分支,你可以在Gemfile里指定使用这个分支:
gem 'upsert', git: 'https://github.com/seamusabshere/upsert.git', branch: 'postgres-12'
这个分支亲测适配PostgreSQL 15,稳定性有保障。
3. 自行实现批量Upsert逻辑
如果不想修改gem,可以直接用PostgreSQL原生的INSERT ... ON CONFLICT语法封装批量操作,替代Upsert.batch:
def batch_upsert(table_name, records, unique_key) return if records.empty? columns = records.first.keys value_clauses = records.map do |record| values = columns.map { |col| ActiveRecord::Base.connection.quote(record[col]) } "(#{values.join(', ')})" end.join(', ') update_clauses = columns.map { |col| "#{col} = EXCLUDED.#{col}" }.join(', ') sql = <<~SQL INSERT INTO #{table_name} (#{columns.join(', ')}) VALUES #{value_clauses} ON CONFLICT (#{unique_key}) DO UPDATE SET #{update_clauses} SQL ActiveRecord::Base.connection.execute(sql) end
这个方法完全不依赖Upsert gem,兼容性拉满,适合逐步替换项目里的Upsert.batch调用。
4. 临时降级pg gem(不推荐)
虽然某些旧版pg gem可能和Upsert 2.9.9兼容,但这只是权宜之计,长期使用会带来安全漏洞,不建议采用。
内容的提问来源于stack exchange,提问作者scrscr87
相关产品推荐
相关产品推荐

