rails-architecture

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Modern Rails 8 Architecture Patterns

现代Rails 8架构模式

Overview

概述

Rails 8 follows "convention over configuration" with a layered architecture that separates concerns. This skill guides architectural decisions for clean, maintainable code.
Rails 8遵循「约定优于配置」原则,采用关注点分离的分层架构。本技能为编写整洁、可维护的代码提供架构决策指导。

Architecture Decision Tree

架构决策树

Where should this code go?
├─ Is it view/display formatting?
│   └─ → Presenter (see: rails-presenter skill)
├─ Is it complex business logic?
│   └─ → Service Object (see: rails-service-object skill)
├─ Is it a complex database query?
│   └─ → Query Object (see: rails-query-object skill)
├─ Is it shared behavior across models?
│   └─ → Concern (see: rails-concern skill)
├─ Is it authorization logic?
│   └─ → Policy (see: authorization-pundit skill)
├─ Is it reusable UI with logic?
│   └─ → ViewComponent (see: viewcomponent-patterns skill)
├─ Is it async/background work?
│   └─ → Job (see: solid-queue-setup skill)
├─ Is it a complex form (multi-model, wizard)?
│   └─ → Form Object (see: form-object-patterns skill)
├─ Is it a transactional email?
│   └─ → Mailer (see: action-mailer-patterns skill)
├─ Is it real-time/WebSocket communication?
│   └─ → Channel (see: action-cable-patterns skill)
├─ Is it data validation only?
│   └─ → Model (see: rails-model-generator skill)
└─ Is it HTTP request/response handling only?
    └─ → Controller (see: rails-controller skill)
Where should this code go?
├─ Is it view/display formatting?
│   └─ → Presenter (see: rails-presenter skill)
├─ Is it complex business logic?
│   └─ → Service Object (see: rails-service-object skill)
├─ Is it a complex database query?
│   └─ → Query Object (see: rails-query-object skill)
├─ Is it shared behavior across models?
│   └─ → Concern (see: rails-concern skill)
├─ Is it authorization logic?
│   └─ → Policy (see: authorization-pundit skill)
├─ Is it reusable UI with logic?
│   └─ → ViewComponent (see: viewcomponent-patterns skill)
├─ Is it async/background work?
│   └─ → Job (see: solid-queue-setup skill)
├─ Is it a complex form (multi-model, wizard)?
│   └─ → Form Object (see: form-object-patterns skill)
├─ Is it a transactional email?
│   └─ → Mailer (see: action-mailer-patterns skill)
├─ Is it real-time/WebSocket communication?
│   └─ → Channel (see: action-cable-patterns skill)
├─ Is it data validation only?
│   └─ → Model (see: rails-model-generator skill)
└─ Is it HTTP request/response handling only?
    └─ → Controller (see: rails-controller skill)

Layer Interaction Flow

层交互流程

┌─────────────────────────────────────────────────────────────┐
│                        REQUEST                               │
└─────────────────────────┬───────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                     CONTROLLER                               │
│  • Authenticate (Authentication concern)                     │
│  • Authorize (Policy)                                        │
│  • Parse params                                              │
│  • Delegate to Service/Query                                 │
└──────────┬─────────────────────────────────┬────────────────┘
           │                                 │
           ▼                                 ▼
┌─────────────────────┐           ┌─────────────────────┐
│      SERVICE        │           │       QUERY         │
│  • Business logic   │           │  • Complex queries  │
│  • Orchestration    │           │  • Aggregations     │
│  • Transactions     │           │  • Reports          │
└──────────┬──────────┘           └──────────┬──────────┘
           │                                 │
           ▼                                 ▼
┌─────────────────────────────────────────────────────────────┐
│                        MODEL                                 │
│  • Validations  • Associations  • Scopes  • Callbacks       │
└─────────────────────────┬───────────────────────────────────┘
           ┌──────────────┴──────────────┐
           ▼                             ▼
┌─────────────────────┐       ┌─────────────────────┐
│     PRESENTER       │       │    VIEW COMPONENT   │
│  • Formatting       │       │  • Reusable UI      │
│  • Display logic    │       │  • Encapsulated     │
└──────────┬──────────┘       └──────────┬──────────┘
           │                             │
           └──────────────┬──────────────┘
┌─────────────────────────────────────────────────────────────┐
│                       RESPONSE                               │
└─────────────────────────────────────────────────────────────┘

ASYNC FLOWS:
┌─────────────────────┐       ┌─────────────────────┐
│        JOB          │       │      CHANNEL        │
│  • Background work  │       │  • Real-time        │
│  • Solid Queue      │       │  • WebSockets       │
└─────────────────────┘       └─────────────────────┘

EMAIL FLOWS:
┌─────────────────────┐
│       MAILER        │
│  • Transactional    │
│  • Notifications    │
└─────────────────────┘
See layer-interactions.md for detailed examples.
┌─────────────────────────────────────────────────────────────┐
│                        REQUEST                               │
└─────────────────────────┬───────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                     CONTROLLER                               │
│  • Authenticate (Authentication concern)                     │
│  • Authorize (Policy)                                        │
│  • Parse params                                              │
│  • Delegate to Service/Query                                 │
└──────────┬─────────────────────────────────┬────────────────┘
           │                                 │
           ▼                                 ▼
┌─────────────────────┐           ┌─────────────────────┐
│      SERVICE        │           │       QUERY         │
│  • Business logic   │           │  • Complex queries  │
│  • Orchestration    │           │  • Aggregations     │
│  • Transactions     │           │  • Reports          │
└──────────┬──────────┘           └──────────┬──────────┘
           │                                 │
           ▼                                 ▼
┌─────────────────────────────────────────────────────────────┐
│                        MODEL                                 │
│  • Validations  • Associations  • Scopes  • Callbacks       │
└─────────────────────────┬───────────────────────────────────┘
           ┌──────────────┴──────────────┐
           ▼                             ▼
┌─────────────────────┐       ┌─────────────────────┐
│     PRESENTER       │       │    VIEW COMPONENT   │
│  • Formatting       │       │  • Reusable UI      │
│  • Display logic    │       │  • Encapsulated     │
└──────────┬──────────┘       └──────────┬──────────┘
           │                             │
           └──────────────┬──────────────┘
┌─────────────────────────────────────────────────────────────┐
│                       RESPONSE                               │
└─────────────────────────────────────────────────────────────┘

ASYNC FLOWS:
┌─────────────────────┐       ┌─────────────────────┐
│        JOB          │       │      CHANNEL        │
│  • Background work  │       │  • Real-time        │
│  • Solid Queue      │       │  • WebSockets       │
└─────────────────────┘       └─────────────────────┘

EMAIL FLOWS:
┌─────────────────────┐
│       MAILER        │
│  • Transactional    │
│  • Notifications    │
└─────────────────────┘
详情示例请查看 layer-interactions.md

Layer Responsibilities

各层职责

LayerResponsibilityShould NOT contain
ControllerHTTP, params, responseBusiness logic, queries
ModelData, validations, relationsDisplay logic, HTTP
ServiceBusiness logic, orchestrationHTTP, display logic
QueryComplex database queriesBusiness logic
PresenterView formatting, badgesBusiness logic, queries
PolicyAuthorization rulesBusiness logic
ComponentReusable UI encapsulationBusiness logic
JobAsync processingHTTP, display logic
FormComplex form handlingPersistence logic
MailerEmail compositionBusiness logic
ChannelWebSocket communicationBusiness logic
层级职责不应包含的内容
ControllerHTTP处理、参数解析、响应返回业务逻辑、查询语句
Model数据管理、验证、关联关系展示逻辑、HTTP处理
Service业务逻辑、流程编排HTTP处理、展示逻辑
Query复杂数据库查询业务逻辑
Presenter视图格式化、标识处理业务逻辑、查询语句
Policy授权规则业务逻辑
Component可复用UI封装业务逻辑
Job异步处理HTTP处理、展示逻辑
Form复杂表单处理持久化逻辑
Mailer邮件内容组合业务逻辑
ChannelWebSocket通信业务逻辑

Project Directory Structure

项目目录结构

app/
├── channels/            # Action Cable channels
├── components/          # ViewComponents (UI + logic)
├── controllers/
│   └── concerns/        # Shared controller behavior
├── forms/               # Form objects
├── helpers/             # Simple view helpers (avoid)
├── jobs/                # Background jobs (Solid Queue)
├── mailers/             # Action Mailer classes
├── models/
│   └── concerns/        # Shared model behavior
├── policies/            # Pundit authorization
├── presenters/          # View formatting
├── queries/             # Complex queries
├── services/            # Business logic
│   └── result.rb        # Shared Result class
└── views/
    └── layouts/
        └── mailer.html.erb  # Email layout
app/
├── channels/            # Action Cable 通道
├── components/          # ViewComponents(UI + 逻辑)
├── controllers/
│   └── concerns/        # 共享控制器行为
├── forms/               # Form Object
├── helpers/             # 简单视图助手(尽量避免使用)
├── jobs/                # 后台任务(Solid Queue)
├── mailers/             # Action Mailer 类
├── models/
│   └── concerns/        # 共享模型行为
├── policies/            # Pundit 授权
├── presenters/          # 视图格式化
├── queries/             # 复杂查询
├── services/            # 业务逻辑
│   └── result.rb        # 共享Result类
└── views/
    └── layouts/
        └── mailer.html.erb  # 邮件布局

Core Principles

核心原则

1. Skinny Controllers

1. 精简控制器(Skinny Controllers)

Controllers should only:
  • Authenticate/authorize
  • Parse params
  • Call service/query
  • Render response
ruby
undefined
控制器应仅负责:
  • 身份验证/授权
  • 参数解析
  • 调用Service/Query
  • 渲染响应
ruby
undefined

GOOD: Thin controller

推荐:精简控制器

class OrdersController < ApplicationController def create result = Orders::CreateService.new.call( user: current_user, params: order_params )
if result.success?
  redirect_to result.data, notice: t(".success")
else
  flash.now[:alert] = result.error
  render :new, status: :unprocessable_entity
end
end end
class OrdersController < ApplicationController def create result = Orders::CreateService.new.call( user: current_user, params: order_params )
if result.success?
  redirect_to result.data, notice: t(".success")
else
  flash.now[:alert] = result.error
  render :new, status: :unprocessable_entity
end
end end

BAD: Fat controller with business logic

不推荐:包含业务逻辑的臃肿控制器

class OrdersController < ApplicationController def create @order = Order.new(order_params) @order.user = current_user
if @order.valid?
  inventory_available = @order.items.all? do |item|
    Product.find(item.product_id).inventory >= item.quantity
  end

  if inventory_available
    # ... more logic
  end
end
end end
undefined
class OrdersController < ApplicationController def create @order = Order.new(order_params) @order.user = current_user
if @order.valid?
  inventory_available = @order.items.all? do |item|
    Product.find(item.product_id).inventory >= item.quantity
  end

  if inventory_available
    # ... 更多逻辑
  end
end
end end
undefined

2. Rich Models, Smart Services

2. 丰富模型,智能服务(Rich Models, Smart Services)

Models handle:
  • Validations
  • Associations
  • Scopes
  • Simple derived attributes
Services handle:
  • Multi-model operations
  • External API calls
  • Complex business rules
  • Transactions across models
模型负责:
  • 数据验证
  • 关联关系
  • 作用域
  • 简单派生属性
服务负责:
  • 跨模型操作
  • 外部API调用
  • 复杂业务规则
  • 跨模型事务

3. Result Objects for Services

3. 服务返回统一Result对象

All services return a consistent Result object:
ruby
class Result
  attr_reader :data, :error, :code

  def initialize(success:, data: nil, error: nil, code: nil)
    @success = success
    @data = data
    @error = error
    @code = code
  end

  def success? = @success
  def failure? = !@success
end
所有服务返回格式一致的Result对象:
ruby
class Result
  attr_reader :data, :error, :code

  def initialize(success:, data: nil, error: nil, code: nil)
    @success = success
    @data = data
    @error = error
    @code = code
  end

  def success? = @success
  def failure? = !@success
end

4. Multi-Tenancy by Default

4. 默认支持多租户

All queries scoped through account:
ruby
undefined
所有查询需通过账号进行范围限定:
ruby
undefined

GOOD: Scoped through account

推荐:通过账号限定范围

def index @events = current_account.events.recent end
def index @events = current_account.events.recent end

BAD: Unscoped query

不推荐:无范围限定的查询

def index @events = Event.where(user_id: current_user.id) end
undefined
def index @events = Event.where(user_id: current_user.id) end
undefined

When NOT to Abstract (Avoid Over-Engineering)

无需抽象的场景(避免过度设计)

SituationKeep It SimpleDon't Create
Simple CRUD (< 10 lines)Keep in controllerService object
Used only onceInline the codeAbstraction
Simple query with 1-2 conditionsModel scopeQuery object
Basic text formattingHelper methodPresenter
Single model form
form_with model:
Form object
Simple partial without logicPartialViewComponent
场景保持简洁无需创建
简单CRUD(少于10行)保留在控制器中Service Object
仅使用一次的代码内联编写抽象层
仅含1-2个条件的简单查询模型作用域Query Object
基础文本格式化助手方法Presenter
单模型表单
form_with model:
Form Object
无逻辑的简单局部视图局部视图ViewComponent

Signs of Over-Engineering

过度设计的表现

ruby
undefined
ruby
undefined

OVER-ENGINEERED: Service for simple save

过度设计:为简单保存操作创建服务

class Users::UpdateEmailService def call(user, email) user.update(email: email) # Just do this in controller! end end
class Users::UpdateEmailService def call(user, email) user.update(email: email) # 直接在控制器中处理即可! end end

KEEP IT SIMPLE

保持简洁

class UsersController < ApplicationController def update if @user.update(user_params) redirect_to @user else render :edit end end end
undefined
class UsersController < ApplicationController def update if @user.update(user_params) redirect_to @user else render :edit end end end
undefined

When TO Abstract

需要抽象的场景

SignalAction
Same code in 3+ placesExtract to concern/service
Controller action > 15 linesExtract to service
Model > 300 linesExtract concerns
Complex conditionalsExtract to policy/service
Query joins 3+ tablesExtract to query object
Form spans multiple modelsExtract to form object
信号操作
相同代码出现在3个及以上位置提取为Concern/Service
控制器方法超过15行提取为Service
模型代码超过300行提取为Concern
复杂条件判断提取为Policy/Service
查询关联3个及以上表提取为Query Object
表单涉及多个模型提取为Form Object

Pattern Selection Guide

模式选择指南

Use Service Objects When:

何时使用Service Object:

  • Logic spans multiple models
  • External API calls needed
  • Complex business rules
  • Need consistent error handling
  • Logic reused across controllers/jobs
→ See rails-service-object skill for details.
  • 逻辑涉及多个模型
  • 需要调用外部API
  • 存在复杂业务规则
  • 需要统一的错误处理
  • 逻辑需在控制器/任务间复用
→ 详情请查看 rails-service-object 技能。

Use Query Objects When:

何时使用Query Object:

  • Complex SQL/ActiveRecord queries
  • Aggregations and statistics
  • Dashboard data
  • Reports
→ See rails-query-object skill for details.
  • 复杂SQL/ActiveRecord查询
  • 数据聚合与统计
  • 仪表盘数据展示
  • 报表生成
→ 详情请查看 rails-query-object 技能。

Use Presenters When:

何时使用Presenter:

  • Formatting data for display
  • Status badges with colors
  • Currency/date formatting
  • Conditional display logic
→ See rails-presenter skill for details.
  • 为展示格式化数据
  • 带颜色标识的状态标签
  • 货币/日期格式化
  • 条件展示逻辑
→ 详情请查看 rails-presenter 技能。

Use Concerns When:

何时使用Concern:

  • Shared validations across models
  • Common scopes (e.g.,
    Searchable
    )
  • Shared callbacks (e.g.,
    HasUuid
    )
  • Keep it single-purpose!
→ See rails-concern skill for details.
  • 模型间共享验证规则
  • 通用作用域(如
    Searchable
  • 共享回调(如
    HasUuid
  • 确保单一职责!
→ 详情请查看 rails-concern 技能。

Use ViewComponents When:

何时使用ViewComponent:

  • Reusable UI with logic
  • Complex partials
  • Need testable views
  • Cards, tables, badges
→ See viewcomponent-patterns skill for details.
  • 带逻辑的可复用UI
  • 复杂局部视图
  • 需要可测试的视图
  • 卡片、表格、标签等组件
→ 详情请查看 viewcomponent-patterns 技能。

Use Form Objects When:

何时使用Form Object:

  • Multi-model forms
  • Wizard/multi-step forms
  • Search/filter forms
  • Contact forms (no persistence)
→ See form-object-patterns skill for details.
  • 多模型表单
  • 分步向导表单
  • 搜索/筛选表单
  • 无需持久化的联系表单
→ 详情请查看 form-object-patterns 技能。

Use Policies When:

何时使用Policy:

  • Resource authorization
  • Role-based access
  • Action permissions
  • Scoped collections
→ See authorization-pundit skill for details.
  • 资源授权
  • 基于角色的访问控制
  • 操作权限管理
  • 范围限定的集合
→ 详情请查看 authorization-pundit 技能。

Rails 8 Specific Features

Rails 8专属特性

Authentication (Built-in Generator)

身份验证(内置生成器)

bash
bin/rails generate authentication
Uses
has_secure_password
with Session model, Current class, and password reset flow.
→ See authentication-flow skill for details.
bash
bin/rails generate authentication
基于
has_secure_password
实现,包含Session模型、Current类和密码重置流程。
→ 详情请查看 authentication-flow 技能。

Background Jobs (Solid Queue)

后台任务(Solid Queue)

Database-backed job processing, no Redis required.
→ See solid-queue-setup skill for details.
基于数据库的任务处理,无需依赖Redis。
→ 详情请查看 solid-queue-setup 技能。

Real-time (Action Cable + Solid Cable)

实时通信(Action Cable + Solid Cable)

WebSocket support with database-backed adapter.
→ See action-cable-patterns skill for details.
支持WebSocket,采用数据库适配器。
→ 详情请查看 action-cable-patterns 技能。

Caching (Solid Cache)

缓存(Solid Cache)

Database-backed caching, no Redis required.
→ See caching-strategies skill for details.
基于数据库的缓存,无需依赖Redis。
→ 详情请查看 caching-strategies 技能。

Other Rails 8 Defaults

Rails 8其他默认特性

FeaturePurpose
PropshaftAsset pipeline (replaces Sprockets)
ImportmapJavaScript without bundling
KamalDocker deployment
ThrusterHTTP/2 proxy with caching
特性用途
Propshaft资源管道(替代Sprockets)
Importmap无需打包的JavaScript管理
KamalDocker部署工具
Thruster带缓存的HTTP/2代理

Anti-Patterns to Avoid

需要避免的反模式

Anti-PatternProblemSolution
God ModelModel > 500 linesExtract services/concerns
Fat ControllerLogic in controllersMove to services
Callback HellComplex model callbacksUse services
Helper SoupMassive helper modulesUse presenters/components
N+1 QueriesUnoptimized queriesUse
.includes()
, query objects
Stringly TypedMagic strings everywhereUse constants, enums
Premature AbstractionService for 3 linesKeep in controller
→ See performance-optimization skill for N+1 detection.
反模式问题解决方案
上帝模型模型代码超过500行提取为Service/Concern
臃肿控制器逻辑写在控制器中迁移至Service
回调地狱复杂的模型回调使用Service
助手混乱庞大的助手模块使用Presenter/Component
N+1查询未优化的查询使用
.includes()
、Query Object
字符串硬编码到处都是魔法字符串使用常量、枚举
过早抽象为3行代码创建Service保留在控制器中
→ 详情请查看 performance-optimization 技能中的N+1查询检测。

Testing Strategy by Layer

按层级划分的测试策略

LayerTest TypeFocus
ModelUnitValidations, scopes, methods
ServiceUnitBusiness logic, edge cases
QueryUnitQuery results, tenant isolation
PresenterUnitFormatting, HTML output
ControllerRequestIntegration, HTTP flow
ComponentComponentRendering, variants
PolicyUnitAuthorization rules
FormUnitValidations, persistence
SystemE2ECritical user paths
→ See tdd-cycle skill for TDD workflow.
层级测试类型重点
Model单元测试验证规则、作用域、方法
Service单元测试业务逻辑、边缘场景
Query单元测试查询结果、租户隔离
Presenter单元测试格式化、HTML输出
Controller请求测试集成、HTTP流程
Component组件测试渲染、变体
Policy单元测试授权规则
Form单元测试验证、持久化
System端到端测试关键用户路径
→ 详情请查看 tdd-cycle 技能中的TDD工作流。

Quick Reference

快速参考

New Feature Checklist

新功能开发检查清单

  1. Model - Define data structure
  2. Policy - Add authorization rules
  3. Service - Create for complex logic (if needed)
  4. Query - Add for complex queries (if needed)
  5. Controller - Keep it thin!
  6. Form - Use for multi-model forms (if needed)
  7. Presenter - Format for display
  8. Component - Build reusable UI
  9. Mailer - Add transactional emails (if needed)
  10. Job - Add background processing (if needed)
  1. Model - 定义数据结构
  2. Policy - 添加授权规则
  3. Service - 复杂逻辑场景下创建(如有需要)
  4. Query - 复杂查询场景下添加(如有需要)
  5. Controller - 保持精简!
  6. Form - 多模型表单场景下使用(如有需要)
  7. Presenter - 为展示格式化数据
  8. Component - 构建可复用UI
  9. Mailer - 添加事务性邮件(如有需要)
  10. Job - 添加后台处理(如有需要)

Refactoring Signals

重构信号

SignalAction
Model > 300 linesExtract concern or service
Controller action > 15 linesExtract service
View logic in helpersUse presenter
Repeated query patternsExtract query object
Complex partial with logicUse ViewComponent
Form with multiple modelsUse form object
Same code in 3+ placesExtract to shared module
信号操作
模型代码超过300行提取为Concern或Service
控制器方法超过15行提取为Service
视图逻辑写在助手中使用Presenter
查询模式重复出现提取为Query Object
带逻辑的复杂局部视图使用ViewComponent
表单涉及多个模型使用Form Object
相同代码出现在3个及以上位置提取为共享模块

Related Skills

相关技能

CategorySkills
Data Layerrails-model-generator, rails-query-object, database-migrations
Business Logicrails-service-object, rails-concern, form-object-patterns
Presentationrails-presenter, viewcomponent-patterns
Controllersrails-controller, api-versioning
Authauthentication-flow, authorization-pundit
Backgroundsolid-queue-setup, action-mailer-patterns
Real-timeaction-cable-patterns, hotwire-patterns
Performancecaching-strategies, performance-optimization
I18ni18n-patterns
Testingtdd-cycle
分类技能
数据层rails-model-generator, rails-query-object, database-migrations
业务逻辑rails-service-object, rails-concern, form-object-patterns
展示层rails-presenter, viewcomponent-patterns
控制器rails-controller, api-versioning
认证授权authentication-flow, authorization-pundit
后台处理solid-queue-setup, action-mailer-patterns
实时通信action-cable-patterns, hotwire-patterns
性能优化caching-strategies, performance-optimization
国际化i18n-patterns
测试tdd-cycle

References

参考资料

  • See layer-interactions.md for layer communication patterns
  • See service-patterns.md for service object patterns
  • See query-patterns.md for query object patterns
  • See error-handling.md for error handling strategies
  • See testing-strategy.md for comprehensive testing
  • 层交互模式详情请查看 layer-interactions.md
  • Service Object模式详情请查看 service-patterns.md
  • Query Object模式详情请查看 query-patterns.md
  • 错误处理策略详情请查看 error-handling.md
  • 全面测试策略详情请查看 testing-strategy.md