Inertia Rails Architecture is a server-driven solution for building pages, forms, navigation, or data refresh in Rails applications using Inertia.js and React. It is designed for developers who want to manage routing, data, and authentication on the server side.
$ npx skills add https://github.com/inertia-rails/skills --skill inertia-rails-architectureInertia Rails Architecture is a Claude Code plugin designed to guide developers building server-driven Rails applications with Inertia.js. It detects and corrects outdated or incorrect patterns in the Inertia Rails stack, including proper redirect handling for external URLs, form component usage, TypeScript configuration, and controller patterns. The plugin supports React, Vue 3, and Svelte frontends with integrated shadcn component adapters. It helps teams maintain consistent architecture across controllers, forms, pages, and testing while leveraging server-side routing, data management, and authentication.
Install using the command provided in the installation section.
Building forms with server-driven architecture
Managing data refresh without client-side routing
Integrating React components in Rails apps using Inertia.js
$ npx skills add https://github.com/inertia-rails/skills --skill inertia-rails-architecturegit clone https://github.com/inertia-rails/skillsCopy the install command above and run it in your terminal.
Launch Claude Code, Cursor, or your preferred AI coding agent.
Use the prompt template or examples below to test the skill.
Adapt the skill to your specific use case and workflow.
Design a [COMPANY] [INDUSTRY] web application using Inertia Rails Architecture. Create a server-driven page with React components, including: 1) A form to [SPECIFIC ACTION, e.g., 'submit user feedback'] with validation 2) Navigation links to key sections 3) A data refresh mechanism for [DATA TYPE, e.g., 'customer orders'] 4) Authentication checks for [ROLE, e.g., 'admin users']. Use Rails controllers to handle routing and data fetching, and React for the UI. Provide code snippets for both backend and frontend.
# Inertia Rails Architecture: Feedback Dashboard
## Backend (Rails Controller)
```ruby
class FeedbackController < ApplicationController
before_action :authenticate_user!
before_action :authorize_admin, only: [:index]
def index
@feedbacks = Feedback.includes(:user).order(created_at: :desc)
render inertia: 'Feedback/Index', props: {
feedbacks: @feedbacks.as_json(only: [:id, :content, :rating, :created_at],
include: { user: { only: [:name, :email] } })
}
end
def create
@feedback = current_user.feedbacks.new(feedback_params)
if @feedback.save
render inertia: 'Feedback/Index', props: {
feedbacks: Feedback.latest(10),
flash: { success: 'Feedback submitted successfully!' }
}
else
render inertia: 'Feedback/New', props: {
errors: @feedback.errors,
form_data: params
}, status: :unprocessable_entity
end
end
private
def feedback_params
params.require(:feedback).permit(:content, :rating)
end
end
```
## Frontend (React Component)
```jsx
import { usePage } from '@inertiajs/inertia-react';
import { Inertia } from '@inertiajs/inertia';
const FeedbackForm = () => {
const { errors, flash } = usePage().props;
const [form, setForm] = useState({ content: '', rating: 5 });
const handleSubmit = (e) => {
e.preventDefault();
Inertia.post('/feedback', form, {
onSuccess: () => setForm({ content: '', rating: 5 })
});
};
return (
<div className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Submit Feedback</h1>
{flash.success && (
<div className="bg-green-100 p-4 rounded mb-6">
{flash.success}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700">Content</label>
<textarea
value={form.content}
onChange={(e) => setForm({...form, content: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
{errors.content && <p className="mt-1 text-sm text-red-600">{errors.content}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Rating</label>
<select
value={form.rating}
onChange={(e) => setForm({...form, rating: parseInt(e.target.value)})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
>
{[1,2,3,4,5].map(r => (
<option key={r} value={r}>{r} Stars</option>
))}
</select>
</div>
<button type="submit" className="px-4 py-2 bg-blue-600 text-white rounded-md">Submit</button>
</form>
<div className="mt-12">
<h2 className="text-xl font-semibold mb-4">Recent Feedback</h2>
<ul className="space-y-4">
{feedbacks.map(fb => (
<li key={fb.id} className="p-4 border rounded-lg">
<div className="flex justify-between">
<span className="font-medium">{fb.user.name}</span>
<span className="text-yellow-500">{'★'.repeat(fb.rating)}</span>
</div>
<p className="mt-1">{fb.content}</p>
<span className="text-sm text-gray-500">
{new Date(fb.created_at).toLocaleString()}
</span>
</li>
))}
</ul>
</div>
</div>
);
};
export default FeedbackForm;
```Take a free 3-minute scan and get personalized AI skill recommendations.
Take free scan