buffalo迁移文件须用buffalo pop generate fizz生成并置于models/migrations/,命名含时间戳前缀(如20260928152233_add_status_to_users.up.fizz),时间戳为执行顺序唯一依据;fizz语法需用抽象类型(如"string")、显式声明主键与外键;执行前停buffalo dev,用soda migrate up -e development运行,预览则加-d参数,回滚用soda migrate down -e development。

Buffalo 项目的数据迁移不是“写完就跑”,而是依赖严格命名、正确 DSL 语法和明确的执行链路。不按约定来,soda migrate 会静默跳过文件,或执行错乱的 SQL。
迁移文件怎么生成和放哪
必须用 buffalo pop generate fizz 命令生成,不能手建空文件或复制旧文件。
- 命令示例:
buffalo pop generate fizz add_status_to_users - 生成路径固定为
models/migrations/,文件名形如20260928152233_add_status_to_users.up.fizz - 时间戳是唯一排序依据——手动删零(如把
20260928152233改成2026928152233)会导致 Buffalo 完全忽略该文件 - 文件后缀必须是
.up.fizz或.down.fizz,写成.up.sql或.fizz会被跳过,且不报错
fizz 语法写表结构要注意什么
fizz 不是 SQL 模板,它是跨数据库抽象层,类型、主键、外键都得用它定义的语义,否则生成的 SQL 在 PostgreSQL 和 MySQL 上行为可能不一致。
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
- 列类型只能用抽象名:
"string"、"uuid"、"boolean"、"timestamp",不能写"VARCHAR(255)"或"SERIAL" - UUID 主键要显式声明:
t.Column("id", "uuid", {"primary": true}),否则默认仍是integer - 外键必须先有字段,再调用
t.ForeignKey(),例如:t.Column("user_id", "uuid", {})后接t.ForeignKey("user_id", "users", {"on_delete": "cascade"}) - 添加非空字段时,若表已有数据,
{"null": false}会失败;应分三步:加可空字段 →exec("UPDATE ... SET ...")补默认值 →alter_column(..., {"null": false})
如何安全执行和回滚迁移
buffalo db migrate 是静默自动执行的,开发中调试迁移必须用底层 soda CLI,否则看不到 SQL、无法中断、也无法回滚。
- 预览将执行的 SQL(不连库、不修改数据):
soda migrate up -d -e development;注意:若database.yml中无development块,soda 会 fallback 到test环境,极易误操作 - 真正执行迁移:
soda migrate up -e development;运行前务必停掉buffalo dev,否则它会在后台自动触发一次静默迁移 - 回滚上一次:
soda migrate down -e development;但前提是对应.down.fizz文件存在且逻辑正确——比如add_column的反向操作是drop_column,不是remove_column(后者根本不存在) - 数据变更类操作(如
exec("UPDATE users SET status = 'active'"))必须在.down.fizz中手动还原,Buffalo 不推导、不校验对称性
为什么执行后提示 “no migrations to run”
这不是迁移文件的问题,而是连接或状态层面的失配,最容易被当成“脚本没写对”而反复改 fizz 内容。
- 最常见原因:
pop.Connection配置未指向目标数据库,或database.yml中当前环境(如development)块缺失/格式错误 -
soda migrate status -e development查看已应用列表,如果为空,说明 Pop 根本没读到任何迁移记录——此时检查schema_migrations表是否存在、是否为空,以及连接用户是否有读写权限 - SQLite 用户注意:若
database.yml中 path 路径含相对路径(如../dev.sqlite),而当前工作目录不在项目根目录,soda 会创建一个空的新库,导致“找不到表”却提示“no migrations to run”
迁移的本质是状态同步,不是代码执行。时间戳、文件名、up/down 对称性、连接配置这四点只要有一处脱节,整个链条就断在你看不见的地方。










