• בלוג
  • חיבור ריאקט וריילס עם Inertia

חיבור ריאקט וריילס עם Inertia

23/10/2025

יש מפתחי ריילס שממש לא אוהבים FrontEnd ויעשו הכל כדי לוותר על כתיבת JavaScript, ויש אחרים שהסיבה שלהם לקום בבוקר היא הפרונט אנד ו Rails אצלם נבחר פשוט כי הוא נותן פיתרון נוח לצד השרת. אם אתם שייכים למחנה השני סיכוי טוב שמאוד תאהבו את ספריית inertia. זו ספריה שמחברת בצורה טובה את קוד הפרונט אנד לאפליקציית Rails. אינרציה היא מתחרה של React On Rails ומתמקדת בניווט בתוך היישום ובהעברת מידע מצד השרת לצד הלקוח. בפוסט זה נראה את עקרונות העבודה המרכזיים של אינרציה.

1. יצירת הפרויקט

בשביל ליצור פרויקט Rails עם Inertia אני משתמש בפקודות הבאות:

$ rails new inertia-demo
$ bundle add inertia_rails
$ bin/rails generate inertia:install

הפקודה האחרונה מריצה wizard בו אני צריך לבחור את הפריימוורק בו אני רוצה לעבוד. אני בוחר ריאקט לדוגמה זו אבל המנגנון תומך גם ב vue ו svelte.

לאחר סיום ה wizard יש לי בתיקיית app/javascript מספר תיקיות חדשות: assets, entrypoints ו pages. אפשר להוסיף עוד תיקיות ככל שתרצו. נקודת הכניסה לאפליקציה היא הקובץ entrypoints/application.js.

2. דף אינרציה ראשון שלי

הדף הראשון באינרציה למעשה נוצר כבר מתוך ה wizard. הוא נקרא InertiaExample ואנחנו מוצאים את הקוד שלו בקובץ app/javascript/pages/InertiaExample.tsx. בואו נקרא אותו יחד:

import { Head } from '@inertiajs/react'
import { useState } from 'react'

import inertiaSvg from '/assets/inertia.svg'
import reactSvg from '/assets/react.svg'
import viteRubySvg from '/assets/vite_ruby.svg'

import cs from './InertiaExample.module.css'

export default function InertiaExample({ name }: { name: string }) {
  const [count, setCount] = useState(0)

  return (
    <>
      <Head title="Inertia + Vite Ruby + React Example" />

      <div className={cs.root}>
        <h1 className={cs.h1}>Hello {name}!</h1>

        <div>
          <a href="https://inertia-rails.dev" target="_blank">
            <img className={cs.logo} src={inertiaSvg} alt="Inertia logo" />
          </a>
          <a href="https://vite-ruby.netlify.app" target="_blank">
            <img
              className={`${cs.logo} ${cs.vite}`}
              src={viteRubySvg}
              alt="Vite Ruby logo"
            />
          </a>
          <a href="https://react.dev" target="_blank">
            <img
              className={`${cs.logo} ${cs.react}`}
              src={reactSvg}
              alt="React logo"
            />
          </a>
        </div>

        <h2 className={cs.h2}>Inertia + Vite Ruby + React</h2>

        <div className="card">
          <button
            className={cs.button}
            onClick={() => setCount((count) => count + 1)}
          >
            count is {count}
          </button>
          <p>
            Edit <code>app/frontend/pages/InertiaExample.jsx</code> and save to
            test HMR
          </p>
        </div>
        <p className={cs.readTheDocs}>
          Click on the Inertia, Vite Ruby, and React logos to learn more
        </p>
      </div>
    </>
  )
}

דבר ראשון שקופץ לעין הוא יצירת הקומפוננטה:

export default function InertiaExample({ name }: { name: string }) {

בשביל ליצור את העמוד יש להעביר משתנה name. תזכרו את זה כי תכף נחזור אליו כדי להבין מאיפה הוא מגיע.

השימוש ב useState רגיל לגמרי לריאקט ומלמד אותנו שקומפוננטות ריאקט הן קומפוננטות צד לקוח - אינרציה תומך ב Server Side Rendering אבל לא ב React Server Components. גם לא ראיתי התיחסות בתיעוד לנושא ה Caching אחרי SSR כך שנראה שה Use Case היותר פופולרי הוא אפליקציות צד-לקוח.

הקומפוננטה המיוחדת Head מאפשרת למלא תוכן באלמנטים בראש העמוד ולכן השורה:

<Head title="Inertia + Vite Ruby + React Example" />

קובעת את ה title. בשביל שזה יעבוד הם הכניסו לקובץ app/views/layouts/application.html.erb את השורה:

<title inertia><%= content_for(:title) || "Inertia Demo" %></title>

אינרציה תומך ב CSS Modules ולכן מבנה הקלאסים:

import cs from './InertiaExample.module.css'

...
<div className={cs.root}>

וזה מסיים את הקומפוננטה הראשונה שלנו.

בשביל לראות את העמוד נלך לפי הכללים של ריילס. בקובץ config/routes.rb אני מוצא את השורה:

get 'inertia-example', to: 'inertia_example#index'

ובקונטרולר app/controllers/inertia_example_controller.rb אני מוצא את ההגדרה:

class InertiaExampleController < ApplicationController
  def index
    render inertia: 'InertiaExample', props: {
      name: params.fetch(:name, 'World'),
    }
  end
end

וזו גם התשובה לשאלה שהתחלנו איתה את הקריאה - מאיפה מגיע הפרמטר name. באינרציה, הפרמטרים לקומפוננטת העמוד מגיעים מהקונטרולר שמפעיל render, וכך גם שם העמוד להצגה.

3. הוספת קומפוננטה

בואו נעדכן את העמוד נוציא את מונה הלחיצות לקומפוננטה שלו ונשים אותו כמה פעמים על הדף. בעבודה עם קומפוננטות אינרציה עובד בדיוק כמו ריאקט. אני יוצר תיקייה חדשה בשם app/javascript/components בתוכה שם את הקובץ Counter.tsx ובו התוכן:

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)
  return (
   <div className="flex flex-col items-center justify-center h-screen bg-gray-100">
      <h1 className="text-3xl font-bold mb-4">Counter: {count}</h1>
      <div className="space-x-4">
        <button
          onClick={() => setCount(count - 1)}
          className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition"
        >
          -
        </button>
        <button
          onClick={() => setCount(count + 1)}
          className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition"
        >
          +
        </button>
        <button
          onClick={() => setCount(0)}
          className="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600 transition"
        >
          Reset
        </button>
      </div>
    </div>
  )
}

ואז בקומפוננטה InertiaExample אני מוסיף פקודת import:

import Counter from '@/components/Counter';

ושימוש בקומפוננטה:

<Counter />
<Counter />
<Counter />

4. דף אינרציה שני וניווט ביניהם

לאינרציה יש עוד כח על ובנוסף להיותה ספריית תבניות היא מחליפה גם את React Router ומאפשרת ניווט צד לקוח בין דפים. בואו נראה איך זה עובד.

אני מעדכן את config/routes.rb כדי שיכיל את שני הנתיבים:

get 'inertia-example', to: 'inertia_example#index', as: :home
get 'inertia-about', to: 'inertia_example#about', as: :about

לאחר מכן אני מעדכן את inertia_example_controller.rb לתוכן הבא:

# frozen_string_literal: true

class InertiaExampleController < ApplicationController
  def index
    render inertia: 'InertiaExample', props: {
      name: params.fetch(:name, 'World'),
      about_path:,
    }
  end

  def about
    render inertia: 'About', props: {
      home_path:,
    }
  end
end

אני יוצר עמוד חדש בקובץ app/javascript/pages/About.tsx עם התוכן הבא:

import { Link } from '@inertiajs/react'

export default function About({
  home_path 
}: {
  home_path: string,
}) {
  return (
    <div>
      <Link href={home_path}>Back home</Link>
    </div>
  )
}

ומעדכן את דף הבית בקובץ InertiaExample.tsx ומוסיף גם לו את הלינק:

export default function InertiaExample({ name, about_path }:
                                       { name: string,
                                         about_path: staring }) {

  return (
    <>
      <Head title="Inertia + Vite Ruby + React Example" />

      <div className={cs.root}>
        <Link href={about_path}>About Us</Link>

עכשיו נראה מה קרה פה:

  1. הקונטרולר מעביר את הנתיבים לקומפוננטות. הנתיבים מוגדרים בתור פונקציות (בסגנון ריילס) כך שאם השמות עצמם יוחלפו בעתיד לא נצטרך לעדכן מחרוזות באפליקציה.

  2. קומפוננטת Link מייצרת ניווט צד לקוח.

כשלוחצים על הלינק מדף הבית למעבר לדף אודות הדפדפן מבצע בקשת JSON ומקבל את התוכן הבא בלבד:

{
  "component": "About",
  "props": {
    "errors": {},
    "home_path": "/inertia-example"
  },
  "url": "/inertia-about",
  "version": "d114e02a9a610c261738bf4254648a71b3fce993",
  "encryptHistory": true,
  "clearHistory": false
}

וכן אנחנו כבר מבינים מהדוגמה כאן שבברירת מחדל אינרציה לא מפצל את קבצי ה JavaScript שלנו לפי דפים. הם כן תומכים במנגנון של פיצול קוד אם ממש נרצה אבל פשוט לא מפעילים אותו לכל פרויקט חדש.

5. מה הלאה

אינרציה כוללת עוד המון יכולות שלא הספקתי לסקור כאן כמו טיפול בהגשת טפסים, העלאת קבצים, ריענון אוטומטי של מידע (polling), ניהול מיקום הגלילה ועוד. אפשר למצוא המון דוגמאות בתיעוד שלהם כאן:

https://inertia-rails.dev/

אבל האמת שמעבר למעטפת של ניתוב והצגת דפים מדובר בסך הכל באפליקציית Client Side React כך שאפשר להשתמש בכל הספריות והיכולות שאנחנו מכירים מעבודה עם ריאקט ו vite. בצד השרת ריילס יתפקד כמו שרת API שבאופן אוטומטי יודע להחזיר קומפוננטה או JSON לפי דרישה.

בהשוואה ל React On Rails אינרציה נראה הרבה יותר פשוט ומינימליסטי. הוא לא מתאים לאפליקציות גדולות שצריכות Server Side Rendering או אופטימיזציות לבניה אבל באפליקציות צד לקוח הוא ייתן תוצאה מהירה וטובה.