关于 rails-refactorer
rails-refactorer 是用于重构 Rails 应用的技能指南,结合 Rails 约定、Ruby 惯用写法和 Sandi Metz 规则。它也涵盖测试维护与生产环境迁移安全,并规定重构结果的报告格式。
主要功能
- 01变更前分析代码与测试
- 02遵循 Rails 控制器和模型约定
- 03应用 Sandi Metz 规则与 Ruby 惯用写法
- 04重构期间维护测试覆盖
- 05检查迁移安全性与可逆性
- 06报告变更、测试状态和警告
适用场景
- 01重构 Rails 控制器和模型
- 02拆分复杂的服务操作
- 03检查迁移的数据丢失与锁表风险
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill rails-refactorer安装后在 Claude Code 中输入/rails-refactorer确认已加载。
详细介绍
Rails 重构器
重构方法
1. 先分析,再修改
开始任何重构前:
- 彻底阅读现有代码
- 确认现有测试覆盖情况(
spec/或test/) - 了解代码的用途和上下文
- 检查代码库中现有的模式
2. 遵循 Rails 约定
控制器:
- 保持控制器精简(仅负责协调)
- 使用 before_action 进行通用设置
- 限制为 7 个 RESTful 操作;自定义操作应新建控制器
- 使用强参数
# Before: Custom action
class MessagesController < ApplicationController
def archive
@message = Message.find(params[:id])
@message.update(archived: true)
end
end
# After: Dedicated controller
class Messages::ArchivesController < ApplicationController
def create
@message = Message.find(params[:message_id])
@message.update(archived: true)
end
end
模型:
- 将业务逻辑放在模型中
- 使用 concern 共享行为
- 使用作用域处理常见查询
- 使用语义明确的关联命名
# Before
belongs_to :user
# After
belongs_to :author, class_name: "User"
服务对象(适用时):
- 用于复杂的多步骤操作
- 用于涉及多个模型的操作
- 保持单一职责
3. 遵循 Sandi Metz 规则
| 规则 | 限制 | 做法 |
|---|---|---|
| 类长度 | 100 行 | 拆分类 |
| 方法长度 | 5 行 | 拆分方法 |
| 参数数量 | 最多 4 个 | 使用参数对象 |
| 控制器对象 | 1 个 | 使用外观对象 |
4. 遵循 Ruby 惯用写法
优先使用:
# Guard clauses
return unless user.active?
# Semantic methods
items.any?
email.present?
# Symbol to proc
users.map(&:name)
# Hash shorthand (Ruby 3.x)
{ name:, email: }
避免使用:
# Nested conditionals
if user
if user.active?
# ...
end
end
# Manual checks
items.length > 0
email != nil && email != ""
5. 保持测试覆盖
- 在重构前后运行测试
- 如果接口发生变化,则更新测试
- 为拆分出的类/方法添加测试
- 绝不破坏现有测试
迁移安全性
重构涉及迁移时,应检查其在生产环境中的安全性、数据保留情况和可逆性。
安全工具
推荐的 gem:
# Gemfile
gem "strong_migrations" # Catches dangerous operations
gem "database_consistency" # Validates model <-> DB constraints
gem "anchor_migrations" # DDL lock timeout protection
可逆性
# PROBLEM: Irreversible migration
def change
remove_column :users, :legacy_id
end
# SOLUTION: Explicit up/down with data preservation
def up
execute "CREATE TABLE legacy_user_ids AS SELECT id, legacy_id FROM users"
remove_column :users, :legacy_id
end
def down
add_column :users, :legacy_id, :integer
execute "UPDATE users SET legacy_id = (SELECT legacy_id FROM legacy_user_ids WHERE legacy_user_ids.id = users.id)"
end
安全的列操作
# PROBLEM: Adding NOT NULL locks table
add_column :users, :status, :string, null: false
# SOLUTION: Three-step migration
add_column :users, :status, :string
User.update_all(status: 'active')
change_column_null :users, :status, false
长时间运行的操作
# PROBLEM: Locks table during index creation
add_index :orders, :customer_id
# SOLUTION: Concurrent index (PostgreSQL)
disable_ddl_transaction!
add_index :orders, :customer_id, algorithm: :concurrently
数据丢失场景
| 操作 | 风险 | 安全替代方案 |
|---|---|---|
| 更改列类型 | 截断 | 添加新列、迁移数据,再删除旧列 |
| 删除列 | 数据丢失 | 先归档,再删除 |
| 重命名列 | 应用出错 | 添加列 + 回填数据 + 删除旧列 |
| 更改精度 | 数据丢失 | 仅扩大精度,绝不缩小 |
迁移审查清单
- 迁移可逆,或明确实现了 down?
- 破坏性更改前是否保留了数据?
- 长时间运行的操作是否使用
algorithm: :concurrently? - 是否安全地添加了 NOT NULL(允许为空 -> 回填数据 -> 添加约束)?
- strong_migrations 是否通过?
- 是否为 DDL 配置了锁定超时?
输出格式
重构后,请提供:
- 摘要 - 重构了什么以及原因
- 更改 - 修改的文件及关键更改
- 测试状态 - 确认测试仍然通过
- 警告 - 潜在问题或需要后续处理的事项
评论
支持 Markdown