inertia-rails-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInertia Rails Architecture
Inertia Rails架构
Server-driven architecture for Rails + Inertia.js + React when building pages,
forms, navigation, or data refresh. Inertia is NOT a traditional SPA — the
server owns routing, data, and auth. React handles rendering only.
适用于Rails + Inertia.js + React的服务端驱动架构,用于构建页面、表单、导航或实现数据刷新。Inertia并非传统SPA——服务器掌控路由、数据和认证,React仅负责渲染。
The Core Mental Model
核心思维模型
The server is the source of truth. React receives data as props and renders UI.
There is no client-side router, no global state store, no API layer.
Before building any feature, ask:
- Where does the data come from? → If server: controller prop. If user interaction: .
useState - Who owns this state? → If it's in the URL or DB: server owns it (use props). If it's ephemeral UI: React owns it.
- Am I reaching for a React/SPA pattern? → Check the decision matrix below first — Inertia likely has a server-driven equivalent.
服务器是唯一可信数据源。React接收数据作为props并渲染UI。这里没有客户端路由,没有全局状态存储,也没有API层。
在构建任何功能之前,请先问自己:
- 数据来自哪里? → 如果来自服务器:使用控制器props。如果来自用户交互:使用。
useState - 谁拥有这个状态? → 如果状态存储在URL或数据库中:由服务器拥有(使用props)。如果是临时UI状态:由React拥有。
- 我是否在使用React/SPA的传统模式? → 请先查看下方的决策矩阵——Inertia很可能有对应的服务端驱动替代方案。
Decision Matrix
决策矩阵
| Need | Solution | NOT This |
|---|---|---|
| Page data from server | Controller props | useEffect + fetch |
| Global data (auth, config) | | React Context / Redux |
| Flash messages / toasts | Rails | inertia_share / React state |
| Form submission | | fetch/axios + useState |
| Navigate between pages | | react-router / window.location |
| Refresh specific data | | React Query / SWR |
| Expensive server data | | useEffect + loading state |
| Infinite scroll | | Client-side pagination |
| Stable reference data | | Cache in React state |
| Real-time updates (core) | ActionCable + | Polling with setInterval |
| Simple polling (MVP/prototyping) | | setInterval + router.reload |
| URL-driven UI state (dialogs, tabs) | Controller reads | useEffect + window.location |
| Ephemeral UI state | | Server props |
| External API calls | Dedicated API endpoint | Mixing with Inertia props |
| 需求 | 解决方案 | 禁止做法 |
|---|---|---|
| 来自服务器的页面数据 | 控制器props | useEffect + fetch |
| 全局数据(认证、配置) | | React Context / Redux |
| 提示消息/通知框 | Rails | inertia_share / React状态 |
| 表单提交 | | fetch/axios + useState |
| 页面间导航 | | react-router / window.location |
| 刷新特定数据 | | React Query / SWR |
| 耗时的服务器数据 | | useEffect + 加载状态 |
| 无限滚动 | | 客户端分页 |
| 稳定的参考数据 | | 在React状态中缓存 |
| 实时更新(核心方案) | ActionCable + | 使用setInterval轮询 |
| 简单轮询(MVP/原型开发) | | setInterval + router.reload |
| URL驱动的UI状态(弹窗、标签页) | 控制器读取 | useEffect + window.location |
| 临时UI状态 | | 服务器props |
| 外部API调用 | 专用API端点 | 与Inertia props混合使用 |
Rules (by impact)
规则(按影响程度排序)
| # | Impact | Rule | WHY |
|---|---|---|---|
| 1 | CRITICAL | Never useEffect+fetch for page data | Inertia re-renders the full component on navigation; a useEffect fetch creates a second data lifecycle that drifts from props and causes stale UI |
| 2 | CRITICAL | Never check auth client-side | Auth state in React can be spoofed; server-side checks are the only real gate. Client-side "guards" give false security |
| 3 | CRITICAL | Use | |
| 4 | HIGH | Use | |
| 5 | HIGH | Use partial reloads, not React Query/SWR | React Query adds a second cache layer that conflicts with Inertia's page-based caching and versioning |
| 5b | HIGH | Use | |
| 6 | HIGH | Use | Context re-renders consumers on every change; shared props are per-request and integrated with partial reloads |
| 7 | HIGH | Use Rails flash for notifications, not shared props | Flash auto-clears after one response; shared props persist until explicitly changed, causing stale toasts |
| 8 | MEDIUM | Use deferred/optional props for expensive queries | Blocks initial render otherwise — user sees blank page until slow query finishes |
| 9 | MEDIUM | Use persistent layouts for state preservation | Without persistent layout, layout remounts on every navigation — scroll position, audio playback, and component state are lost |
| 10 | MEDIUM | Keep React components as renderers, not data fetchers | Mixing data-fetching into components makes them untestable and breaks Inertia's server-driven model |
| 序号 | 影响程度 | 规则 | 原因 |
|---|---|---|---|
| 1 | 关键 | 绝对不要使用useEffect+fetch获取页面数据 | Inertia在导航时会重新渲染整个组件,useEffect发起的fetch会创建第二个数据生命周期,与props产生偏差,导致UI数据过期 |
| 2 | 关键 | 绝对不要在客户端校验认证状态 | React中的认证状态可以被伪造;只有服务端校验才是真正的安全屏障。客户端“守卫”会带来虚假的安全感 |
| 3 | 关键 | 使用 | |
| 4 | 高 | 使用 | |
| 5 | 高 | 使用局部刷新,不要用React Query/SWR | React Query会添加第二个缓存层,与Inertia基于页面的缓存和版本控制机制冲突 |
| 5b | 高 | 仅在MVP阶段使用 | |
| 6 | 高 | 使用 | Context在每次变化时都会重新渲染所有消费者;共享props是基于请求的,并且与局部刷新集成 |
| 7 | 高 | 使用Rails flash处理通知消息,不要用共享props | Flash会在一次响应后自动清除;共享props会一直保留直到显式修改,导致通知消息过期 |
| 8 | 中 | 对耗时查询使用延迟/可选props | 否则会阻塞初始渲染——用户会看到空白页面直到慢查询完成 |
| 9 | 中 | 使用持久化布局来保留状态 | 如果没有持久化布局,每次导航时布局都会重新挂载——滚动位置、音频播放和组件状态都会丢失 |
| 10 | 中 | 让React组件仅负责渲染,不要处理数据获取 | 在组件中混合数据获取逻辑会让组件无法测试,并且破坏Inertia的服务端驱动模型 |
Skill Map
技能映射
Common workflows span multiple skills — load all listed for complete coverage:
| Workflow | Load these skills |
|---|---|
| New page with props | |
| Form with validation | |
| shadcn form inputs | |
| Flash toasts | |
| Deferred/lazy data | |
| URL-driven dialog/tabs | |
| Alba serialization | |
| Testing controllers | |
常见工作流涉及多个技能——请加载所有列出的技能以获得完整覆盖:
| 工作流 | 需加载的技能 |
|---|---|
| 带props的新页面 | |
| 带校验的表单 | |
| shadcn表单输入框 | |
| Flash通知框 | |
| 延迟/懒加载数据 | |
| URL驱动的弹窗/标签页 | |
| Alba序列化 | |
| 测试控制器 | |
References
参考资料
MANDATORY — READ ENTIRE FILE before building a new Inertia page or feature:
(~430 lines) — full-stack examples for
each pattern in the decision matrix above.
references/AGENTS.mdMANDATORY — READ ENTIRE FILE when unsure which Inertia pattern to use:
(~70 lines) — flowcharts
for choosing between prop types, navigation methods, and data strategies.
references/decision-trees.mdDo NOT load references for quick questions about a single pattern already
covered in the decision matrix above.
强制要求——在构建新的Inertia页面或功能之前,请完整阅读整个文件:
(约430行)——包含上述决策矩阵中每种模式的全栈示例。
references/AGENTS.md强制要求——当不确定使用哪种Inertia模式时,请完整阅读整个文件:
(约70行)——包含用于选择props类型、导航方法和数据策略的流程图。
references/decision-trees.md请勿加载参考资料来查询决策矩阵中已覆盖的单一模式相关的简单问题。
When You DO Need a Separate API
何时需要独立API
Not everything belongs in Inertia's request cycle. Use a traditional API endpoint when:
| Signal | Why | Example |
|---|---|---|
| Non-browser consumer | Inertia's JSON envelope (component, props, url, version) is designed for the frontend adapter — other consumers can't use it | Mobile API, CLI tools, payment webhooks |
| Large-dataset search | Dataset is too big to load as a prop; each input needs per-keystroke server filtering. Use raw fetch for the search, let Inertia handle post-selection side effects via props. | City/address autocomplete, postal code lookup |
| Binary/streaming response | Inertia can only deliver JSON props. Use a separate route with a standard download response. | PDF/CSV export, file downloads |
并非所有场景都适合Inertia的请求周期。在以下情况请使用传统API端点:
| 信号 | 原因 | 示例 |
|---|---|---|
| 非浏览器客户端 | Inertia的JSON信封(component、props、url、version)是为前端适配器设计的——其他客户端无法使用 | 移动API、CLI工具、支付Webhook |
| 大数据集搜索 | 数据集过大无法作为props加载;每个输入都需要逐按键进行服务器过滤。使用原生fetch处理搜索,让Inertia通过props处理选择后的副作用。 | 城市/地址自动补全、邮政编码查询 |
| 二进制/流式响应 | Inertia仅能传递JSON props。请使用独立路由返回标准下载响应。 | PDF/CSV导出、文件下载 |