rails-stack-conventions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRails Stack Conventions
Rails技术栈约定
When writing or generating code for this project, follow these conventions. Stack: Ruby on Rails, PostgreSQL, Hotwire (Turbo + Stimulus), Tailwind CSS.
Style: If the project uses a linter, treat it as the source of truth for formatting. For cross-cutting design principles (DRY, YAGNI, structured logging, rules by directory), use rails-code-conventions.
在为该项目编写或生成代码时,请遵循以下约定。技术栈:Ruby on Rails、PostgreSQL、Hotwire(Turbo + Stimulus)、Tailwind CSS。
代码风格:如果项目使用代码检查工具(linter),则以其配置为格式标准。对于跨领域的设计原则(DRY、YAGNI、结构化日志、目录规则),请参考rails-code-conventions。
HARD-GATE: Tests Gate Implementation
硬性要求:测试先行
ALL new code MUST have its test written and validated BEFORE implementation.
1. Write the spec: bundle exec rspec spec/[path]_spec.rb
2. Verify it FAILS — output must show the feature does not exist yet
3. ONLY THEN write the implementation code
See rspec-best-practices for the full gate cycle.所有新代码必须在实现前完成测试编写并验证。
1. 编写测试用例:bundle exec rspec spec/[path]_spec.rb
2. 验证测试失败——输出需显示该功能尚未存在
3. 只有完成上述步骤后,才能编写实现代码
完整的测试流程请参考rspec-best-practices。Quick Reference
快速参考
| Aspect | Convention |
|---|---|
| Style | RuboCop project config when present; otherwise Ruby Style Guide, single quotes |
| Models | MVC — service objects for complex logic, concerns for shared behavior |
| Queries | Eager load with |
| Frontend | Hotwire (Turbo + Stimulus); Tailwind CSS |
| Testing | RSpec with FactoryBot; TDD |
| Security | Strong params, guard XSS/CSRF/SQLi; Devise/Pundit for auth |
| 方面 | 约定 |
|---|---|
| 代码风格 | 优先使用项目的RuboCop配置;若无则遵循Ruby Style Guide,使用单引号 |
| 模型 | 遵循MVC架构——复杂逻辑使用服务对象(service objects),共享行为使用concerns |
| 查询 | 使用 |
| 前端 | 使用Hotwire(Turbo + Stimulus);样式采用Tailwind CSS |
| 测试 | 使用RSpec搭配FactoryBot;遵循测试驱动开发(TDD) |
| 安全 | 使用强参数(Strong params),防范XSS/CSRF/SQL注入;认证授权使用Devise/Pundit |
Key Code Patterns
核心代码模式
Hotwire: Turbo Frames
Hotwire: Turbo Frames
erb
<%# Wrap a section to be replaced without a full page reload %>
<turbo-frame id="order-<%= @order.id %>">
<%= render "orders/details", order: @order %>
</turbo-frame>
<%# Link that targets only this frame %>
<%= link_to "Edit", edit_order_path(@order), data: { turbo_frame: "order-#{@order.id}" } %>erb
<%# 包裹需要局部刷新的区域,无需整页重载 %>
<turbo-frame id="order-<%= @order.id %>">
<%= render "orders/details", order: @order %>
</turbo-frame>
<%# 仅指向该frame的链接 %>
<%= link_to "编辑", edit_order_path(@order), data: { turbo_frame: "order-#{@order.id}" } %>Hotwire: Turbo Streams (broadcast from controller)
Hotwire: Turbo Streams(从控制器广播)
ruby
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"order_#{@order.id}",
partial: "orders/order",
locals: { order: @order }
)
end
format.html { redirect_to @order }
endruby
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"order_#{@order.id}",
partial: "orders/order",
locals: { order: @order }
)
end
format.html { redirect_to @order }
endAvoiding N+1 — Eager Loading
避免N+1查询——预加载
ruby
undefinedruby
undefinedBAD — triggers one query per order
错误示例——每个订单都会触发一次查询
@orders = Order.where(user: current_user)
@orders.each { |o| o.line_items.count }
@orders = Order.where(user: current_user)
@orders.each { |o| o.line_items.count }
GOOD — single JOIN via includes
正确示例——通过includes实现单次JOIN查询
@orders = Order.includes(:line_items).where(user: current_user)
undefined@orders = Order.includes(:line_items).where(user: current_user)
undefinedService Object (complex business logic out of the controller)
服务对象(将复杂业务逻辑从控制器中分离)
ruby
undefinedruby
undefinedController stays thin — delegate to service
控制器保持精简——委托给服务对象处理
result = Orders::CreateOrder.call(user: current_user, params: order_params)
if result[:success]
redirect_to result[:order], notice: "Order created"
else
@order = Order.new(order_params)
render :new, status: :unprocessable_entity
end
See **ruby-service-objects** for the full `.call` pattern and response format.result = Orders::CreateOrder.call(user: current_user, params: order_params)
if result[:success]
redirect_to result[:order], notice: "订单创建成功"
else
@order = Order.new(order_params)
render :new, status: :unprocessable_entity
end
完整的`.call`模式和响应格式请参考**ruby-service-objects**。Security
安全规范
- Strong params on every controller action that writes data
- Guard against XSS (use , avoid
html_escape), CSRF (Rails default on), SQLi (use AR query methods orrawfor raw SQL)sanitize_sql - Auth: Devise for authentication, Pundit for authorization
- 所有涉及数据写入的控制器操作必须使用强参数(Strong params)
- 防范XSS攻击(使用,避免
html_escape)、CSRF攻击(Rails默认开启防护)、SQL注入(使用ActiveRecord查询方法,若使用原生SQL需用raw处理)sanitize_sql - 认证授权:使用Devise进行身份认证,Pundit进行权限控制
Common Mistakes
常见错误
| Mistake | Correct approach |
|---|---|
| Business logic in views | Use helpers, presenters, or Stimulus controllers |
| N+1 queries in loops | Eager load with |
| Raw SQL without parameterization | Use AR query methods or |
| Skipping FactoryBot for "quick" test | Fixtures are brittle — always use factories |
| 错误做法 | 正确方式 |
|---|---|
| 在视图中编写业务逻辑 | 使用辅助方法(helpers)、展示器(presenters)或Stimulus控制器 |
| 循环中出现N+1查询 | 在循环前使用 |
| 使用未参数化的原生SQL | 使用ActiveRecord查询方法或 |
| 为了“快速”测试跳过FactoryBot | 固定测试数据(Fixtures)易维护性差——始终使用工厂对象(factories) |
Red Flags
关联技能
- Controller action with more than 15 lines of business logic
- Model with no validations on required fields
- View with embedded Ruby conditionals spanning 10+ lines
- No on associations used in loops
includes - Hardcoded strings that belong in I18n
| 技能 | 适用场景 |
|---|---|
| rails-code-conventions | 参考设计原则、结构化日志和路径特定规则时 |
| rails-code-review | 对照本约定审查现有代码时 |
| ruby-service-objects | 将业务逻辑提取到服务对象中时 |
| rspec-best-practices | 参考测试约定和TDD流程时 |
| rails-architecture-review | 进行超出本约定范围的架构审查时 |
Integration
—
| Skill | When to chain |
|---|---|
| rails-code-conventions | For design principles, structured logging, and path-specific rules |
| rails-code-review | When reviewing existing code against these conventions |
| ruby-service-objects | When extracting business logic into service objects |
| rspec-best-practices | For testing conventions and TDD cycle |
| rails-architecture-review | For structural review beyond conventions |
—