Rails 7中db:schema:load为何依赖硬编码test环境的db:test:purge?
db:schema:load 依赖db:test:purge的疑问与分析 问题概述
简而言之:在Rails 7中,db:schema:load rake任务为何会依赖硬编码了env_name: "test"的db:test:purge任务?
使用场景说明
当前Rails.env为"production",但不会对生产数据库执行破坏性操作,具体场景如下:
- 为某Rails应用开发「按需远程环境」功能
- 应用包含多个数据库,部分存储业务数据,新增的则存储纯技术数据
- 按需环境中,业务数据使用参考环境的专属数据库克隆,技术数据使用空PostgreSQL容器(写时复制克隆有开销,空容器更经济)
- 启动PostgreSQL容器时,会创建数据库和用户,但数据库为空
- 按需环境启动时,首个任务会调用所有数据库的
db:migraterake任务 - 借此任务先执行
db:schema:load:tech_db_1,将Rails应用的数据库结构同步到新增的技术数据库中
核心问题分析
调用db:schema:load时,会先执行若干依赖任务,其中包括针对每个数据库生成的db:test:purge。查看Rails源码可知,该任务依赖check_protected_environments任务,当Rails.env为"production"时会抛出ProtectedEnvironmentError。
这个设计本身合理,错误提示显示可设置DISABLE_DATABASE_ENVIRONMENT_CHECK=1继续操作。但如果执行此设置,db:test:purge会尝试操作测试数据库——因为它硬编码了env_name: "test"。虽然db:test:*类任务硬编码环境有合理理由,但无法理解为何db:schema:load(以及db:setup、db:reset等任务)会依赖这类硬编码环境的任务。
在我看来,check_protected_environments任务已足以防止操作失误,若允许跳过该检查,后续操作应针对预期数据库(而非必然是测试库)执行。
临时解决方案
目前想到的唯一临时办法是,在设置任务中,将应用的测试数据库配置指向实际要操作的数据库地址。这与生产环境无关,无风险,但实现方式较为粗糙。
更新说明
我已在Rails仓库提交Issue,该Issue已被标记为另一Issue的重复项。目前暂无明确答案,后续需关注关联Issue的进展。
内容的提问来源于stack exchange,提问作者aTom

