inertia-rails-architecture

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Inertia 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

决策矩阵

NeedSolutionNOT This
Page data from serverController propsuseEffect + fetch
Global data (auth, config)
inertia_share
+
usePage()
React Context / Redux
Flash messages / toastsRails
flash
+
usePage().flash
inertia_share / React state
Form submission
<Form>
component
fetch/axios + useState
Navigate between pages
<Link>
/
router.visit
react-router / window.location
Refresh specific data
router.reload({ only: [...] })
React Query / SWR
Expensive server data
InertiaRails.defer
useEffect + loading state
Infinite scroll
InertiaRails.scroll
+
<InfiniteScroll>
Client-side pagination
Stable reference data
InertiaRails.once
Cache in React state
Real-time updates (core)ActionCable +
router.reload
Polling with setInterval
Simple polling (MVP/prototyping)
usePoll
(auto-throttles in background tabs)
setInterval + router.reload
URL-driven UI state (dialogs, tabs)Controller reads
params
→ prop,
router.get
to update
useEffect + window.location
Ephemeral UI state
useState
/
useReducer
Server props
External API callsDedicated API endpointMixing with Inertia props
需求解决方案禁止做法
来自服务器的页面数据控制器propsuseEffect + fetch
全局数据(认证、配置)
inertia_share
+
usePage()
React Context / Redux
提示消息/通知框Rails
flash
+
usePage().flash
inertia_share / React状态
表单提交
<Form>
组件
fetch/axios + useState
页面间导航
<Link>
/
router.visit
react-router / window.location
刷新特定数据
router.reload({ only: [...] })
React Query / SWR
耗时的服务器数据
InertiaRails.defer
useEffect + 加载状态
无限滚动
InertiaRails.scroll
+
<InfiniteScroll>
客户端分页
稳定的参考数据
InertiaRails.once
在React状态中缓存
实时更新(核心方案)ActionCable +
router.reload
使用setInterval轮询
简单轮询(MVP/原型开发)
usePoll
(在后台标签页自动节流)
setInterval + router.reload
URL驱动的UI状态(弹窗、标签页)控制器读取
params
→ 转为prop,使用
router.get
更新
useEffect + window.location
临时UI状态
useState
/
useReducer
服务器props
外部API调用专用API端点与Inertia props混合使用

Rules (by impact)

规则(按影响程度排序)

#ImpactRuleWHY
1CRITICALNever useEffect+fetch for page dataInertia re-renders the full component on navigation; a useEffect fetch creates a second data lifecycle that drifts from props and causes stale UI
2CRITICALNever check auth client-sideAuth state in React can be spoofed; server-side checks are the only real gate. Client-side "guards" give false security
3CRITICALUse
<Form>
, not fetch/axios
<Form>
handles CSRF, redirect-following, error mapping, file detection, and history state — fetch duplicates or breaks all of this
4HIGHUse
<Link>
and
router
, not
<a>
or window.location
<a>
triggers a full page reload, destroying all React state and layout persistence
5HIGHUse partial reloads, not React Query/SWRReact Query adds a second cache layer that conflicts with Inertia's page-based caching and versioning
5bHIGHUse
usePoll
only for MVPs; prefer ActionCable for production real-time
usePoll
is convenient but wastes bandwidth — every interval hits the server even when nothing changed. ActionCable pushes only on actual changes
6HIGHUse
inertia_share
for global data, not React Context
Context re-renders consumers on every change; shared props are per-request and integrated with partial reloads
7HIGHUse Rails flash for notifications, not shared propsFlash auto-clears after one response; shared props persist until explicitly changed, causing stale toasts
8MEDIUMUse deferred/optional props for expensive queriesBlocks initial render otherwise — user sees blank page until slow query finishes
9MEDIUMUse persistent layouts for state preservationWithout persistent layout, layout remounts on every navigation — scroll position, audio playback, and component state are lost
10MEDIUMKeep React components as renderers, not data fetchersMixing 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关键使用
<Form>
组件,不要用fetch/axios
<Form>
组件会处理CSRF、重定向跟踪、错误映射、文件检测和历史状态——fetch会重复实现这些功能或导致功能失效
4使用
<Link>
router
,不要用
<a>
或window.location
<a>
会触发整页刷新,销毁所有React状态和布局持久化
5使用局部刷新,不要用React Query/SWRReact Query会添加第二个缓存层,与Inertia基于页面的缓存和版本控制机制冲突
5b仅在MVP阶段使用
usePoll
;生产环境实时更新优先使用ActionCable
usePoll
虽然便捷,但会浪费带宽——即使数据没有变化,每个轮询间隔都会请求服务器。ActionCable仅在数据实际变化时推送更新
6使用
inertia_share
处理全局数据,不要用React Context
Context在每次变化时都会重新渲染所有消费者;共享props是基于请求的,并且与局部刷新集成
7使用Rails flash处理通知消息,不要用共享propsFlash会在一次响应后自动清除;共享props会一直保留直到显式修改,导致通知消息过期
8对耗时查询使用延迟/可选props否则会阻塞初始渲染——用户会看到空白页面直到慢查询完成
9使用持久化布局来保留状态如果没有持久化布局,每次导航时布局都会重新挂载——滚动位置、音频播放和组件状态都会丢失
10让React组件仅负责渲染,不要处理数据获取在组件中混合数据获取逻辑会让组件无法测试,并且破坏Inertia的服务端驱动模型

Skill Map

技能映射

Common workflows span multiple skills — load all listed for complete coverage:
WorkflowLoad these skills
New page with props
inertia-rails-controllers
+
inertia-rails-pages
+
inertia-rails-typescript
Form with validation
inertia-rails-forms
+
inertia-rails-controllers
shadcn form inputs
inertia-rails-forms
+
shadcn-inertia
Flash toasts
inertia-rails-controllers
+
inertia-rails-pages
+
shadcn-inertia
Deferred/lazy data
inertia-rails-controllers
+
inertia-rails-pages
URL-driven dialog/tabs
inertia-rails-controllers
+
inertia-rails-pages
Alba serialization
alba-inertia
+
inertia-rails-typescript
Testing controllers
inertia-rails-testing
+
inertia-rails-controllers
常见工作流涉及多个技能——请加载所有列出的技能以获得完整覆盖:
工作流需加载的技能
带props的新页面
inertia-rails-controllers
+
inertia-rails-pages
+
inertia-rails-typescript
带校验的表单
inertia-rails-forms
+
inertia-rails-controllers
shadcn表单输入框
inertia-rails-forms
+
shadcn-inertia
Flash通知框
inertia-rails-controllers
+
inertia-rails-pages
+
shadcn-inertia
延迟/懒加载数据
inertia-rails-controllers
+
inertia-rails-pages
URL驱动的弹窗/标签页
inertia-rails-controllers
+
inertia-rails-pages
Alba序列化
alba-inertia
+
inertia-rails-typescript
测试控制器
inertia-rails-testing
+
inertia-rails-controllers

References

参考资料

MANDATORY — READ ENTIRE FILE before building a new Inertia page or feature:
references/AGENTS.md
(~430 lines) — full-stack examples for each pattern in the decision matrix above.
MANDATORY — READ ENTIRE FILE when unsure which Inertia pattern to use:
references/decision-trees.md
(~70 lines) — flowcharts for choosing between prop types, navigation methods, and data strategies.
Do NOT load references for quick questions about a single pattern already covered in the decision matrix above.
强制要求——在构建新的Inertia页面或功能之前,请完整阅读整个文件:
references/AGENTS.md
(约430行)——包含上述决策矩阵中每种模式的全栈示例。
强制要求——当不确定使用哪种Inertia模式时,请完整阅读整个文件:
references/decision-trees.md
(约70行)——包含用于选择props类型、导航方法和数据策略的流程图。
请勿加载参考资料来查询决策矩阵中已覆盖的单一模式相关的简单问题。

When You DO Need a Separate API

何时需要独立API

Not everything belongs in Inertia's request cycle. Use a traditional API endpoint when:
SignalWhyExample
Non-browser consumerInertia's JSON envelope (component, props, url, version) is designed for the frontend adapter — other consumers can't use itMobile API, CLI tools, payment webhooks
Large-dataset searchDataset 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 responseInertia 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导出、文件下载