inertia-rails-architecture by inertia-rails/skills
npx skills add https://github.com/inertia-rails/skills --skill inertia-rails-architecture构建页面、表单、导航或数据刷新时,适用于 Rails + Inertia.js + React 的服务器驱动架构。Inertia 并非传统的 SPA —— 服务器拥有路由、数据和认证。React 仅负责渲染。
服务器是唯一可信源。React 接收数据作为 props 并渲染 UI。没有客户端路由器,没有全局状态存储,没有 API 层。
在构建任何功能之前,请思考:
useState。| 需求 | 解决方案 | 不要使用这个 |
|---|---|---|
| 来自服务器的页面数据 | 控制器 props | useEffect + fetch |
| 全局数据(认证、配置) | inertia_share + usePage() |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| React Context / Redux |
| 闪存消息 / 提示 | Rails flash + usePage().flash | inertia_share / React state |
| 表单提交 | <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 state 中 |
| 实时更新(核心) | 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 混合 |
---|---|---|---
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/SWR | React Query 添加了第二层缓存,与 Inertia 基于页面的缓存和版本控制冲突
5b | 高 | 仅对 MVP 使用 usePoll;生产环境实时更新首选 ActionCable | usePoll 很方便但浪费带宽 —— 即使没有变化,每个间隔都会访问服务器。ActionCable 仅在发生实际变化时推送
6 | 高 | 使用 inertia_share 处理全局数据,而不是 React Context | Context 会在每次变化时重新渲染消费者;共享 props 是每个请求的,并与部分重载集成
7 | 高 | 使用 Rails flash 处理通知,而不是共享 props | Flash 在一次响应后自动清除;共享 props 会持续存在直到显式更改,导致过时的提示
8 | 中 | 对昂贵的查询使用延迟/可选 props | 否则会阻塞初始渲染 —— 用户会看到空白页面直到慢查询完成
9 | 中 | 使用持久化布局以保持状态 | 没有持久化布局,布局会在每次导航时重新挂载 —— 滚动位置、音频播放和组件状态会丢失
10 | 中 | 保持 React 组件作为渲染器,而不是数据获取器 | 将数据获取混入组件会使它们不可测试,并破坏 Inertia 的服务器驱动模型
常见工作流涉及多个技能 —— 加载所有列出的技能以获得完整覆盖:
| 工作流 | 加载这些技能 |
|---|---|
| 带 props 的新页面 | inertia-rails-controllers + inertia-rails-pages + inertia-rails-typescript |
| 带验证的表单 | inertia-rails-forms + inertia-rails-controllers |
| shadcn 表单输入 | inertia-rails-forms + shadcn-inertia |
| 闪存提示 | 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 |
强制要求 —— 在构建新的 Inertia 页面或功能前,请完整阅读文件:references/AGENTS.md(约 430 行)—— 上述决策矩阵中每种模式的全栈示例。
强制要求 —— 当不确定使用哪种 Inertia 模式时,请完整阅读文件:references/decision-trees.md(约 70 行)—— 用于在 prop 类型、导航方法和数据策略之间进行选择的流程图。
不要加载参考资料来快速询问已在上方决策矩阵中涵盖的单一模式。
并非所有内容都适合放在 Inertia 的请求周期中。在以下情况使用传统的 API 端点:
| 信号 | 原因 | 示例 |
|---|---|---|
| 非浏览器消费者 | Inertia 的 JSON 信封(component、props、url、version)是为前端适配器设计的 —— 其他消费者无法使用它 | 移动端 API、CLI 工具、支付 webhooks |
| 大数据集搜索 | 数据集太大,无法作为 prop 加载;每个输入都需要按击键进行服务器端过滤。对搜索使用原始 fetch,让 Inertia 通过 props 处理选择后的副作用。 | 城市/地址自动补全、邮政编码查询 |
| 二进制/流式响应 | Inertia 只能传递 JSON props。使用具有标准下载响应的独立路由。 | PDF/CSV 导出、文件下载 |
每周安装量
77
仓库
GitHub 星标
35
首次出现
2026年2月13日
安全审计
安装于
codex76
opencode76
gemini-cli75
github-copilot74
amp73
kimi-cli72
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.
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:
useState.| Need | Solution | NOT This |
|---|---|---|
| Page data from server | Controller props | useEffect + fetch |
| Global data (auth, config) | inertia_share + usePage() | React Context / Redux |
| Flash messages / toasts | Rails 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 calls | Dedicated API endpoint | Mixing with Inertia props |
---|---|---|---
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 <Form>, not fetch/axios | <Form> handles CSRF, redirect-following, error mapping, file detection, and history state — fetch duplicates or breaks all of this
4 | HIGH | Use <Link> and router, not <a> or window.location | <a> triggers a full page reload, destroying all React state and layout persistence
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 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
6 | HIGH | Use for global data, not React Context | 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
Common workflows span multiple skills — load all listed for complete coverage:
| Workflow | Load 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 | + + |
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.
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 |
Weekly Installs
77
Repository
GitHub Stars
35
First Seen
Feb 13, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex76
opencode76
gemini-cli75
github-copilot74
amp73
kimi-cli72
TanStack Query v5 完全指南:React 数据管理、乐观更新、离线支持
2,500 周安装
Elastic Cloud 访问管理技能:用户邀请、角色分配与API密钥管理
201 周安装
LLM结构化输出提取器:从AI响应中提取类型化数据的完整指南
70 周安装
SwiftUI动画完全指南:从Animatable协议到iOS 26的@Animatable宏
195 周安装
Feishu Image Sender - 向飞书/Lark发送图片的CLI工具和Node.js库
193 周安装
如何向AI工作流添加新技能?GitHub技能下载与文档更新完整指南
194 周安装
FPGA开发专家指南:Vivado、SystemVerilog硬件设计优化与高级技术实践
196 周安装
inertia_shareinertia-rails-controllersinertia-rails-pagesshadcn-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 |