rails-stack-conventions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rails 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

快速参考

AspectConvention
StyleRuboCop project config when present; otherwise Ruby Style Guide, single quotes
ModelsMVC — service objects for complex logic, concerns for shared behavior
QueriesEager load with
includes
; never iterate over associations without preloading
FrontendHotwire (Turbo + Stimulus); Tailwind CSS
TestingRSpec with FactoryBot; TDD
SecurityStrong params, guard XSS/CSRF/SQLi; Devise/Pundit for auth
方面约定
代码风格优先使用项目的RuboCop配置;若无则遵循Ruby Style Guide,使用单引号
模型遵循MVC架构——复杂逻辑使用服务对象(service objects),共享行为使用concerns
查询使用
includes
预加载关联数据;绝对不要在未预加载的情况下遍历关联对象
前端使用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 }
end
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 }
end

Avoiding N+1 — Eager Loading

避免N+1查询——预加载

ruby
undefined
ruby
undefined

BAD — 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)
undefined

Service Object (complex business logic out of the controller)

服务对象(将复杂业务逻辑从控制器中分离)

ruby
undefined
ruby
undefined

Controller 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
    html_escape
    , avoid
    raw
    ), CSRF (Rails default on), SQLi (use AR query methods or
    sanitize_sql
    for raw SQL)
  • Auth: Devise for authentication, Pundit for authorization
  • 所有涉及数据写入的控制器操作必须使用强参数(Strong params)
  • 防范XSS攻击(使用
    html_escape
    ,避免
    raw
    )、CSRF攻击(Rails默认开启防护)、SQL注入(使用ActiveRecord查询方法,若使用原生SQL需用
    sanitize_sql
    处理)
  • 认证授权:使用Devise进行身份认证,Pundit进行权限控制

Common Mistakes

常见错误

MistakeCorrect approach
Business logic in viewsUse helpers, presenters, or Stimulus controllers
N+1 queries in loopsEager load with
includes
before the loop
Raw SQL without parameterizationUse AR query methods or
ActiveRecord::Base.sanitize_sql
Skipping FactoryBot for "quick" testFixtures are brittle — always use factories
错误做法正确方式
在视图中编写业务逻辑使用辅助方法(helpers)、展示器(presenters)或Stimulus控制器
循环中出现N+1查询在循环前使用
includes
预加载关联数据
使用未参数化的原生SQL使用ActiveRecord查询方法或
ActiveRecord::Base.sanitize_sql
为了“快速”测试跳过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
    includes
    on associations used in loops
  • Hardcoded strings that belong in I18n
技能适用场景
rails-code-conventions参考设计原则、结构化日志和路径特定规则时
rails-code-review对照本约定审查现有代码时
ruby-service-objects将业务逻辑提取到服务对象中时
rspec-best-practices参考测试约定和TDD流程时
rails-architecture-review进行超出本约定范围的架构审查时

Integration

SkillWhen to chain
rails-code-conventionsFor design principles, structured logging, and path-specific rules
rails-code-reviewWhen reviewing existing code against these conventions
ruby-service-objectsWhen extracting business logic into service objects
rspec-best-practicesFor testing conventions and TDD cycle
rails-architecture-reviewFor structural review beyond conventions