Rails7迁移后schema.rb生成无效索引,导致db:test:prepare执行失败
Rails 7 中 JSON 字段自定义索引导致 schema.rb 语法错误的解决方案
问题场景
- 在 Rails 7 环境下,通过自定义 SQL 迁移为 JSON 字段添加函数索引后,自动生成的
schema.rb索引语句存在语法错误 - 执行命令
RAILS_ENV=test rake db:test:prepare时触发ActiveRecord::StatementInvalid错误 - 手动修改
schema.rb可临时修复,但后续执行迁移后问题会再次出现
相关代码与错误信息
自定义迁移代码
class AddSavedSearchAPIKeyIndex < ActiveRecord::Migration[7.0] def change execute <<~SQL ALTER TABLE saved_searches ADD INDEX ecomm_analyze_api_key (( CAST(configuration->>"$.ecomm_analyze_api_key" as CHAR(255)) COLLATE utf8mb4_bin )) USING BTREE; SQL end end
schema.rb 生成的错误索引语句
t.index "(cast(json_unquote(json_extract(`configuration`,_utf8mb4\\'$.ecomm_analyze_api_key\\')) as char(255) charset utf8mb4) collate utf8mb4_bin)", name: "ecomm_analyze_api_key"
触发的错误信息
ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
解决方案
推荐方案:改用 structure.sql 替代 schema.rb
Rails 的 schema.rb 基于 Ruby DSL,无法完全兼容所有数据库原生 SQL 语法,对于复杂的函数索引支持不足。改用 structure.sql 直接保存数据库原生结构,能准确保留自定义索引的语法:
- 修改
config/application.rb,设置 schema 格式为 SQL:config.active_record.schema_format = :sql - 执行命令生成
db/structure.sql:rails db:structure:dump - 后续测试环境准备使用以下命令替代
db:test:prepare:RAILS_ENV=test rake db:structure:load
临时方案(不推荐):手动修正 schema.rb
如果暂时无法切换到 structure.sql,可以手动将 schema.rb 中的错误索引语句替换为原生 SQL 执行:
# 替换自动生成的 t.index 语句 execute <<~SQL CREATE INDEX ecomm_analyze_api_key ON saved_searches ((CAST(configuration->>"$.ecomm_analyze_api_key" as CHAR(255)) COLLATE utf8mb4_bin)) USING BTREE; SQL
注意:每次执行迁移后都需要重新修改,无法长期解决问题。
问题原因
Rails 的 Schema Dumper 在解析 MySQL 的 JSON 运算符 ->> 时,会将其转换为 json_unquote(json_extract(...)),但转义处理逻辑出错,导致生成的语句中出现多余的转义符(\\')和错误的语法结构,最终触发 MySQL 语法错误。
内容的提问来源于stack exchange,提问作者Overload119
相关产品推荐
相关产品推荐

