--- name: inertia-coder description: Build modern SPAs with Inertia.js and Rails using React, Vue, or Svelte. Use when creating Inertia pages, handling forms with useForm, managing shared props, or implementing client-side routing. Triggers on Inertia.js setup, SPA development, or React/Vue/Svelte with Rails. --- # Inertia.js + Rails Build modern single-page applications using Inertia.js with React/Vue/Svelte and Rails backend. ## When to Use This Skill - Setting up Inertia.js with Rails - Creating Inertia page components - Handling forms with useForm hook - Managing shared props and flash messages - Client-side routing without API complexity - File uploads with progress tracking ## What is Inertia.js? **Inertia.js allows you to build SPAs using classic server-side routing and controllers.** | Approach | Pros | Cons | |----------|------|------| | Traditional Rails Views | Simple, server-rendered | Limited interactivity | | Rails API + React SPA | Full SPA experience | Duplicated routing, complex state | | **Inertia.js** | SPA + server routing | Best of both worlds | ## Quick Setup ```ruby # Gemfile gem 'inertia_rails' gem 'vite_rails' ``` ```bash bundle install rails inertia:install # Choose: React, Vue, or Svelte ``` ```ruby # config/initializers/inertia_rails.rb InertiaRails.configure do |config| config.version = ViteRuby.digest config.share do |controller| { auth: { user: controller.current_user&.as_json(only: [:id, :name, :email]) }, flash: controller.flash.to_hash } end end ``` ## Controller Pattern ```ruby class ArticlesController < ApplicationController def index articles = Article.published.order(created_at: :desc) render inertia: 'Articles/Index', props: { articles: articles.as_json(only: [:id, :title, :excerpt]) } end def create @article = Article.new(article_params) if @article.save redirect_to article_path(@article), notice: 'Article created' else redirect_to new_article_path, inertia: { errors: @article.errors } end end end ``` ## React Page Component ```jsx // app/frontend/pages/Articles/Index.jsx import { Link } from '@inertiajs/react' export default function Index({ articles }) { return (

Articles

{articles.map(article => (

{article.title}

))}
) } ``` ## Forms with useForm ```jsx import { useForm } from '@inertiajs/react' export default function New() { const { data, setData, post, processing, errors } = useForm({ title: '', body: '' }) function handleSubmit(e) { e.preventDefault() post('/articles') } return (
setData('title', e.target.value)} /> {errors.title &&
{errors.title}
}