ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Rails 自定义迁移模板指南:用 lib/templates/migration.rb.tt 定制 Schema Migration 生成器

Rails 自定义迁移模板指南:用 lib/templates/migration.rb.tt 定制 Schema Migration 生成器 文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载本文整理自 TIL 仓库的 rails/customize-template-for-new-schema-migration.md围绕 Rails 迁移生成器展开默认的rails generate migration会使用框架内置的 ERB 模板生成迁移文件而通过在你的 Rails 应用中放置lib/templates/migration.rb.tt即可全局覆盖这份模板让每一次生成的迁移都自带你偏好的结构例如up/down方法加原始 SQL 的骨架。读完本文你将掌握 Rails 生成器的模板解析机制、自定义模板的编写规则以及生成过程中 locals 变量从哪来。Rails 生成器从脚手架到单个迁移文件Rails 提供了一套完整的生成器generator机制既可以用来脚手架出一整块应用model、controller、views、routes 等也可以小到只生成一个迁移文件。本仓库中多处实践都印证了这套机制的存在rails/generate-a-model.md 展示了bin/rails generate model Book title:string是如何一次性产出迁移文件、模型文件甚至还能让rspec-rails这类 gem 钩入生成器额外产出 spec 文件rails/scaffold-auth-functionality-with-rails-8-generator.md 展示了 Rails 8 内置的bin/rails generate authentication生成器在内部再次调用rails generate migration CreateUsers ...的完整链路。迁移文件的生成入口就是下面这条命令$ rails generate migration MakeUserStatusColumnNotNull运行这条命令时Rails 会根据给定的迁移名称在db/migrate/下创建一个时间戳前缀的迁移文件例如db/migrate/20241001000000_make_user_status_column_not_null.rb并基于名称推断出迁移类名MakeUserStatusColumnNotNull→MakeUserStatusColumnNotNull。默认行为Rails 内置的迁移模板当执行迁移生成命令时Rails 会取出框架内置的迁移模板baked-in migration templateactiverecord/lib/rails/generators/active_record/migration/templates/migration.rb.tt这份模板是一份 ERB.tt后缀即 Thor 模板文件它根据传入的迁移名称以及生成器内部设置的其他局部变量渲染出一个标准的迁移文件。默认情况下生成出的迁移会采用change方法风格形如class MakeUserStatusColumnNotNull ActiveRecord::Migration[8.0] def change change_column_null :users, :status, false end end这就是标准行为。不过这份模板并非不可撼动——Rails 允许你在应用内覆盖它。覆盖模板在 lib/templates/migration.rb.tt 中定义自己的迁移骨架要在你的 Rails 应用中替换默认迁移模板只需在应用的lib/templates/目录下创建同名文件lib/templates/migration.rb.tt文件名必须与内置模板保持一致migration.rb.tt这样 Rails 生成器在查找模板时会优先命中应用内的这份自定义模板。你需要遵循模板的基本结构ERB 语法、migration_class_name等变量约定但具体内容可以完全按需改写。需要注意该目录默认不会在新建 Rails 应用中预置需要手动创建lib/templates/目录并放入文件。实战模板up/down 方法 原始 SQL原文档作者的个人偏好是使用#up和#down方法并在迁移中直接写原始 SQL。为此他给出了一份可直接落盘的模板作为每次生成迁移的起点class % migration_class_name % ActiveRecord::Migration[% ActiveRecord::Migration.current_version %] def up execute ~SQL SQL end def down execute ~SQL SQL end end把这段内容保存为lib/templates/migration.rb.tt后再运行$ rails generate migration MakeUserStatusColumnNotNull生成出的迁移文件就会是这种结构你只需在up的 heredoc 中填入正向 SQL、在down的 heredoc 中填入回滚 SQL 即可class MakeUserStatusColumnNotNull ActiveRecord::Migration[8.0] def up execute ~SQL ALTER TABLE users ALTER COLUMN status SET NOT NULL; SQL end def down execute ~SQL ALTER TABLE users ALTER COLUMN status DROP NOT NULL; SQL end end这种写法的优势在于完全掌控 SQLDDL 细节、数据库方言特性不再受 ActiveRecord 迁移 DSL 抽象层的限制显式的双向迁移up/down成对出现方向清晰适合与change无法表达的操作例如需要自定义索引、复杂约束或不可逆但可手写回滚的变更时up/down是最直白的表达方式。仓库中的相关笔记也佐证了这一风格的合理性rails/make-remove-column-migration-reversible.md 指出remove_column单独写进change并不可逆需要补充类型参数而显式的up/down天然不存在这种歧义。模板变量从哪来migration_generator.rb 的 locals自定义模板中使用的% migration_class_name %并不是凭空出现的。原文档指出需要看 ActiveRecord 的迁移生成器实现activerecord/lib/rails/generators/active_record/migration/migration_generator.rb从该生成器的create_migration_file方法原文档标注约在第 26–43 行可以看到它负责两件事设置 locals局部变量把migration_class_name、table_name、attributes、migration_action、primary_key_type等值组装成哈希传给模板渲染选定模板文件通过 Thor 的template方法按约定查找模板——先查找lib/templates/migration.rb.tt应用级覆盖未命中则回落到框架内置的migration.rb.tt。从源码结构可以推断模板渲染遵循 Thor 的模板查找优先级应用内的lib/templates/会优先于 gem 内置模板被解析这正是“自定义模板生效”的底层原理。生成过程中迁移类名由你传入的名称推导而来其余变量如table_name、attributes则取决于你是否在命令中附带列定义# 仅指定名称只有迁移类名被设置 $ rails generate migration MakeUserStatusColumnNotNull # 附带字段定义table_name、attributes 等 locals 也会被填充 $ rails generate migration AddStatusToUsers status:boolean模板里可以自由使用这些 ERB 变量例如class % migration_class_name % ActiveRecord::Migration[% ActiveRecord::Migration.current_version %] def change add_column :% table_name %, :status, :boolean end endActiveRecord::Migration.current_version这一调用会在模板渲染时求值自动写入当前 Rails 版本的迁移基类版本号如Migration[8.0]无需手工维护。与 change 方法的取舍仓库中的对照参考自定义为up/down风格后你依然可以随时在该迁移内部改回change只要变更可逆。仓库中的 rails/write-reversible-migration-to-set-default.md 给出了一个很好的对照change_column_default可以用显式up/down分别设置false与nil也可以压缩成单方法的可逆形式def change change_column_default :books, :published, from: nil, to: false end这说明模板决定的是“生成的起点”而具体选择哪种风格仍取决于每次迁移的实际诉求——追求简洁的可逆变更用change需要精细控制 SQL 的用up/down。自定义模板只是让后者成为你的默认起点。此外rails/change-the-nullability-of-a-column.md 展示的change_column_null与 rails/add-timestamptz-columns-with-the-migration-dsl.md 展示的t.column :created_at, :timestamptz都表明当你需要超出 DSL 默认表达的能力如带时区的时间戳列、强制 NOT NULL时掌握底层模板与 SQL 输出是很有价值的技能。验证自定义模板是否生效创建lib/templates/migration.rb.tt后可以用以下方式快速验证# 生成一个迁移并观察输出文件的内容是否为你定义的骨架 $ rails generate migration AddIndexToUsersOnEmail # 然后打开 db/migrate/ 下最新生成的迁移文件检查 # 或在生成后预览不实际落盘部分 Rails 版本支持 dry-run $ rails generate migration AddIndexToUsersOnEmail --pretend如果生成的迁移文件依然沿用change风格请检查模板文件名是否为migration.rb.tt必须与内置模板同名同路径文件是否位于lib/templates/相对于 Rails 应用根目录而非test/或spec/下模板是否为合法的 ERB 语法% %输出、% %控制流。小结Rails 迁移生成器的默认模板藏在 ActiveRecord gem 内部而lib/templates/migration.rb.tt提供了一层应用级的覆盖入口。只需一个同名文件就能让团队所有成员用rails generate migration生成的代码天然符合统一规范——无论是up/down加原始 SQL还是其他任何你期望的骨架。理解migration_generator.rb如何设置 locals 与选择模板是驾驭这套自定义机制的关键。更完整的原始笔记见 rails/customize-template-for-new-schema-migration.md相关的迁移实践可继续翻阅本仓库 rails 目录下的其余迁移主题。赞分享文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载相关推荐Devise生成器模板自定义Migration与控制器Devise生成器模板自定义Migration与控制器 Devise作为Ruby on Rails生态中最流行的认证解决方案提供了强大的生成器工具来帮助开发认证鉴权后端Fast JSON API 生成器系统Rails 模板和自定义生成器终极指南 Fast JSON API 生成器系统Rails 模板和自定义生成器终极指南 欢迎来到 Fast JSON API 生成器系统的完整教程Fast JS后端Firecracker CPU 模板CPU Templates完全指南静态模板、自定义模板与 vCPU 特性定制Firecracker CPU 模板CPU Templates完全指南静态模板、自定义模板与 vCPU 特性定制 Firecracker 允许用户通过 C虚拟化云原生创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进