Современная веб-разработка на Ruby on Rails: Hotwire и InertiaJS

Этот курс посвящен созданию интерактивных веб-приложений на Rails 7+ с использованием двух современных подходов к фронтенду. Вы научитесь работать с нативным стеком Hotwire и интегрировать JavaScript-фреймворки через протокол InertiaJS.

1. Основы современного Rails: архитектура монолита и настройка окружения

Основы современного Rails: архитектура монолита и настройка окружения

Добро пожаловать в курс «Современная веб-разработка на Ruby on Rails: Hotwire и InertiaJS». Мы начинаем путешествие в мир одного из самых продуктивных и элегантных фреймворков современности. Возможно, вы слышали, что «Rails мёртв» или что будущее только за микросервисами. Однако реальность такова: Ruby on Rails переживает свой ренессанс. Концепция «The One Person Framework» (фреймворк для одного человека) позволяет небольшим командам создавать продукты, которые раньше требовали усилий целых отделов разработки.

В этой вводной статье мы разберем философию современного Rails, поймем, почему монолитная архитектура снова в моде, и подготовим наше рабочее место для создания мощных веб-приложений.

Философия Rails и Величественный Монолит

Ruby on Rails построен на двух фундаментальных принципах, которые отличают его от многих других инструментов:

  • DRY (Don't Repeat Yourself) — «Не повторяйся». Каждая часть знаний должна иметь единственное, непротиворечивое и авторитетное представление в системе.
  • Convention over Configuration — «Соглашение важнее конфигурации». Rails принимает множество решений за вас. Если вы следуете соглашениям (например, называете таблицы в базе данных во множественном числе, а классы моделей — в единственном), вам не нужно писать сотни строк конфигурационных файлов.
  • Возвращение к монолиту

    Долгое время индустрия двигалась в сторону разделения: отдельный API на бэкенде (Go, Node.js, Python) и отдельное SPA (Single Page Application) на фронтенде (React, Vue). Это отличный подход для гигантов вроде Google или Facebook, но для стартапов и среднего бизнеса он часто приносит избыточную сложность.

    Современный Rails проповедует идею The Majestic Monolith (Величественный Монолит). Это архитектура, где весь код — от работы с базой данных до рендеринга HTML и управления JavaScript — живет в одном репозитории и развертывается как единое целое.

    !Сравнение архитектуры Монолита и Микросервисов/SPA

    Преимущества такого подхода:

    * Скорость разработки: Не нужно синхронизировать API контракты между фронтендом и бэкендом. * Простота деплоя: Вы разворачиваете одно приложение, а не десять. * Целостность данных: Вся логика валидации и обработки данных находится в одном месте.

    Именно здесь на сцену выходят технологии Hotwire и InertiaJS, которые мы будем изучать в этом курсе. Они позволяют создавать интерактивные интерфейсы, не разрывая связь с монолитом и не превращая приложение в сложный SPA.

    Архитектура MVC в контексте Rails

    Rails следует классическому паттерну MVC (Model-View-Controller), но со своими особенностями. Давайте разберем, как проходит жизненный цикл запроса в Rails-приложении.

  • Маршрутизатор (Router): Принимает входящий HTTP-запрос (например, GET /articles/1) и решает, какой контроллер должен его обработать.
  • Контроллер (Controller): «Дирижер» оркестра. Он получает запрос, обращается к модели за данными и передает эти данные в представление.
  • Модель (Model): Слой бизнес-логики и данных. Модель общается с базой данных, проверяет валидность данных и выполняет сложные вычисления.
  • Представление (View): Шаблон (обычно HTML с вкраплениями Ruby-кода), который формирует ответ пользователю.
  • В современном Rails к этому добавляются фоновые задачи (Jobs), каналы реального времени (ActionCable) и компоненты фронтенда, но ядро остается неизменным.

    Настройка окружения

    Для комфортной разработки на Ruby on Rails вам потребуется Unix-подобная система (macOS или Linux). Если вы используете Windows, настоятельно рекомендуется использовать WSL2 (Windows Subsystem for Linux). Попытки нативной разработки на Windows часто приводят к проблемам с совместимостью гемов (библиотек).

    Шаг 1: Установка Ruby

    Никогда не используйте системный Ruby, предустановленный в вашей ОС. Используйте менеджер версий. Самые популярные:

    * rbenv (рекомендуемый выбор за простоту) * RVM * asdf (универсальный менеджер для разных языков)

    Пример установки Ruby 3.3.0 через rbenv:

    Шаг 2: База данных

    Rails по умолчанию поддерживает SQLite, но для серьезной разработки стандартом де-факто является PostgreSQL. Он надежен, мощен и используется в продакшене большинством Rails-проектов.

    Убедитесь, что у вас установлен PostgreSQL и запущен сервер базы данных.

    Шаг 3: Node.js и Yarn (Опционально, но полезно)

    Хотя современный Rails (начиная с версии 7) позволяет обходиться без Node.js благодаря Import Maps, для использования InertiaJS или сложного бандлинга JS нам все же понадобятся Node.js и пакетный менеджер Yarn.

    Шаг 4: Установка Rails

    Когда Ruby установлен, установка самого фреймворка — это просто установка гема (пакета Ruby):

    Проверим версию:

    Создание первого приложения

    Давайте создадим каркас нашего будущего приложения. Мы будем использовать PostgreSQL в качестве базы данных.

    Эта команда создаст директорию my_course_app и сгенерирует полную структуру проекта. Давайте заглянем внутрь.

    Структура каталогов

    Rails создает много папок, но не пугайтесь. Вот самые важные на старте:

    * app/ — Здесь живет ваш код. * app/models — Модели (работа с БД). * app/controllers — Контроллеры. * app/views — HTML-шаблоны. * app/javascript — Ваш JS код (точки входа). * config/ — Настройки приложения. * config/routes.rb — Маршрутизация (какой URL куда ведет). * config/database.yml — Настройки подключения к БД. * db/ — Схемы базы данных и миграции. * Gemfile — Список библиотек (гемов), которые использует проект.

    Запуск приложения

    Перед первым запуском нужно создать базу данных (так как мы выбрали PostgreSQL):

    Теперь запустим сервер. В современном Rails часто используется скрипт bin/dev, который запускает не только сервер Rails, но и сборщики CSS/JS (если они есть):

    Если вы используете чистый Rails без сложных сборщиков, достаточно команды:

    Откройте браузер по адресу http://localhost:3000. Вы должны увидеть приветственную страницу Rails.

    Bundler и управление зависимостями

    В корне проекта лежит файл Gemfile. Это манифест всех библиотек, необходимых вашему приложению. Ruby использует систему Bundler для управления ими.

    Если вы видите в инструкции «добавьте гем kaminari», это значит, что нужно добавить строку gem "kaminari" в Gemfile и выполнить команду:

    Эта команда скачает библиотеку и зафиксирует её точную версию в файле Gemfile.lock. Это гарантирует, что на сервере и у других разработчиков будут установлены абсолютно идентичные версии библиотек.

    Заключение

    Мы подготовили фундамент. У нас есть настроенное окружение, понимание архитектуры MVC и созданное приложение. Мы выбрали путь монолита, который позволит нам разрабатывать быстро и эффективно.

    В следующих статьях мы начнем наполнять наше приложение жизнью, изучая, как Hotwire меняет правила игры в интерактивности, и как InertiaJS позволяет интегрировать мощь React/Vue прямо в Rails-монолит без боли создания API.

    Готовы? Проверьте свои знания в тесте ниже и переходите к следующему уроку!

    2. Экосистема Hotwire: использование Turbo и Stimulus для динамических интерфейсов

    Экосистема Hotwire: использование Turbo и Stimulus для динамических интерфейсов

    В предыдущей статье мы обсудили архитектуру «Величественного Монолита» и настроили окружение для работы с Ruby on Rails. Мы выяснили, что современный Rails позволяет создавать быстрые и отзывчивые приложения без необходимости разделять проект на API и отдельный SPA-фронтенд. Секрет этой магии кроется в Hotwire.

    Hotwire (HTML Over The Wire) — это альтернативный подход к созданию современного веба. Вместо того чтобы отправлять JSON с сервера и рендерить HTML на клиенте (как это делают React или Vue), Hotwire отправляет готовый HTML, который браузер просто вставляет в нужное место. Это позволяет сохранить всю логику шаблонов на сервере, значительно упрощая кодовую базу.

    В этой статье мы подробно разберем два главных столпа Hotwire: Turbo и Stimulus.

    Turbo: Сердце Hotwire

    Turbo — это набор технологий, который ускоряет навигацию по страницам и отправку форм, а также позволяет обновлять части страницы без полной перезагрузки. Он состоит из нескольких компонентов:

  • Turbo Drive
  • Turbo Frames
  • Turbo Streams
  • !Сравнение потока данных в SPA (JSON) и Hotwire (HTML)

    Turbo Drive

    Turbo Drive (ранее известный как Turbolinks) работает автоматически. Когда вы кликаете по ссылке или отправляете форму, Turbo Drive перехватывает этот запрос, отправляет его через AJAX (fetch), получает HTML-ответ, извлекает из него <body> и заменяет текущий <body> новым содержимым.

    Что это дает? * Браузер не перезагружает CSS и JavaScript файлы. * Страницы загружаются мгновенно. * Сохраняется состояние окна (например, позиция скролла).

    Вам практически ничего не нужно делать, чтобы это работало — Turbo Drive включен в Rails по умолчанию.

    Turbo Frames

    Turbo Frames позволяют разбить страницу на независимые контексты. Представьте, что ваша страница — это набор рамок (фреймов). Когда вы кликаете по ссылке внутри рамки, обновляется только содержимое этой рамки, а остальная часть страницы остается нетронутой.

    Это идеально подходит для: * Редактирования комментариев in-place (на месте). * Пагинации списков без перезагрузки шапки и подвала сайта. * Вкладок и модальных окон.

    Пример использования:

    Допустим, у нас есть список сообщений, и мы хотим отредактировать одно из них прямо в списке.

    В представлении (app/views/messages/_message.html.erb):

    Когда пользователь нажмет «Редактировать», Rails вернет страницу с формой редактирования. Если эта форма также обернута в turbo_frame_tag с тем же ID, Turbo автоматически заменит только этот кусок HTML.

    !Принцип работы Turbo Frames: обновление изолированной части страницы

    Turbo Streams

    Если Frames — это обновление по запросу пользователя (клик), то Turbo Streams — это обновление по инициативе сервера или сложные обновления нескольких частей страницы одновременно.

    С помощью Streams вы можете: * Добавить новый комментарий в начало списка (prepend). * Удалить элемент из списка (remove). * Обновить счетчик уведомлений в шапке сайта (update).

    Самое мощное применение Streams — это работа с WebSockets (ActionCable). Вы можете транслировать изменения всем подключенным пользователям в реальном времени, написав всего пару строк кода в модели.

    Пример в модели:

    Stimulus: Скромный JavaScript фреймворк

    Turbo отлично справляется с навигацией и обновлением HTML, но иногда нам нужно чисто клиентское взаимодействие: скрыть/показать элемент, скопировать текст в буфер обмена, запустить анимацию или интегрировать библиотеку карт.

    Здесь на сцену выходит Stimulus. В отличие от React или Vue, Stimulus не пытается управлять всем DOM или рендерить HTML. Он просто «оживляет» уже существующий HTML.

    Основные концепции Stimulus

    Stimulus работает на трех китах:

  • Controllers (Контроллеры) — JavaScript классы, которые управляют поведением.
  • Actions (Действия) — Связывают события DOM (клики, изменения) с методами контроллера.
  • Targets (Цели) — Позволяют контроллеру находить нужные элементы внутри своего скоупа.
  • Пример: Контроллер приветствия

    Давайте создадим простой контроллер, который выводит приветствие при нажатии на кнопку.

  • HTML (View):
  • JavaScript (Controller):
  • Файл app/javascript/controllers/hello_controller.js:

    Почему Stimulus удобен?

    * HTML как источник истины: Вы читаете HTML и сразу видите, какой JS код с ним связан (data-controller, data-action). * Жизненный цикл: Stimulus автоматически подключает контроллеры, когда элементы появляются на странице (даже если они пришли через Turbo Stream), и отключает их при удалении. Отсутствие состояния: Состояние хранится в HTML (в атрибутах data-), а не в переменных JavaScript, что упрощает отладку.

    Как Turbo и Stimulus работают вместе

    Это симбиоз. Turbo доставляет HTML с сервера. Этот HTML уже содержит атрибуты data-controller. Stimulus видит эти атрибуты и автоматически «подключается» к новым элементам.

    Сценарий из жизни:

  • Пользователь отправляет форму создания задачи (Task).
  • Сервер через Turbo Stream добавляет HTML новой задачи в список.
  • В этом HTML есть кнопка «Удалить» с data-controller="confirmation".
  • Stimulus автоматически инициализирует контроллер confirmation для новой кнопки, который будет показывать window.confirm при нажатии.
  • Вам не нужно писать код для инициализации JS для новых элементов — это происходит само собой.

    Заключение

    Экосистема Hotwire возвращает радость в веб-разработку. Вы пишете на Ruby, используете стандартные шаблоны Rails, а получаете интерфейс, который работает так же быстро и плавно, как сложные SPA-приложения. Turbo берет на себя сетевое взаимодействие и обновление DOM, а Stimulus добавляет необходимую интерактивность на клиенте.

    В следующей статье мы рассмотрим альтернативный подход — использование InertiaJS, который позволяет объединить монолит Rails с мощью React или Vue компонентов, если вам все же требуется сложная логика состояния на клиенте.

    3. Внедрение InertiaJS: создание моста между Rails и React/Vue

    Внедрение InertiaJS: создание моста между Rails и React/Vue

    В предыдущих модулях мы погрузились в экосистему Hotwire. Мы увидели, как Turbo и Stimulus позволяют оживлять страницы, оставаясь в рамках классического рендеринга HTML на сервере. Это мощный подход, который покрывает 80-90% потребностей типичных веб-приложений.

    Но что делать с оставшимися 10-20%? Что если ваше приложение требует сложного управления состоянием на клиенте, насыщенных интерактивных карт, драг-н-дроп интерфейсов или вы просто хотите использовать огромную экосистему компонентов React или Vue? Традиционный ответ индустрии на этот вопрос — разделение на микросервисы: Rails превращается в JSON API, а фронтенд становится отдельным SPA (Single Page Application).

    Однако этот путь ведет к резкому возрастанию сложности: вам приходится управлять двумя репозиториями, дублировать логику валидации, настраивать CORS и аутентификацию через токены. Здесь на сцену выходит InertiaJS.

    Что такое InertiaJS?

    InertiaJS — это не фреймворк в привычном понимании. Это, скорее, «клей» или протокол, который соединяет серверный фреймворк (в нашем случае Ruby on Rails) и клиентский фреймворк (React, Vue или Svelte).

    Создатель Inertia, Джонатан Рейнинк, называет этот подход «Современный Монолит». Идея проста: вы строите классическое Rails-приложение с контроллерами, моделями и маршрутизацией, но вместо шаблонов ERB (.html.erb) вы отдаете JavaScript-компоненты.

    Inertia позволяет вам создавать полноценное SPA, полностью исключая необходимость в создании API. Вы получаете мощь React/Vue, сохраняя продуктивность Rails.

    Как это работает?

    В центре философии Inertia лежит концепция, что вы не должны писать HTTP-запросы (fetch/axios) для получения данных. Вместо этого данные передаются в компоненты как props (свойства), точно так же, как в Rails данные передаются в шаблоны через переменные экземпляра.

    !Схема жизненного цикла запросов в InertiaJS: полная загрузка против последующих навигаций

    Механизм работы выглядит так:

  • Первая загрузка: Когда пользователь впервые открывает сайт, Rails отдает полноценную HTML-страницу. Внутри нее подключен JavaScript-бандл и JSON-объект с начальными данными.
  • Навигация: Когда пользователь кликает по ссылке (используя специальный компонент Link от Inertia), браузер не перезагружает страницу. Вместо этого Inertia перехватывает клик и отправляет AJAX-запрос на сервер с заголовком X-Inertia: true.
  • Ответ сервера: Rails видит этот заголовок и вместо HTML возвращает JSON с именем компонента и данными (props).
  • Рендеринг: Inertia на клиенте получает JSON, находит нужный React/Vue компонент и рендерит его с новыми данными, меняя URL в браузере через History API.
  • Настройка Rails для работы с Inertia

    Для начала работы нам потребуется добавить гем inertia_rails и настроить сборщик JavaScript (обычно Vite или Webpacker/Shakapacker, так как React/Vue требуют компиляции).

    Добавим гем в Gemfile:

    После установки зависимостей (bundle install), мы можем начать использовать Inertia в наших контроллерах.

    Контроллеры Rails

    Самое прекрасное в Inertia — это то, как мало меняется ваш бэкенд-код. Взгляните на стандартный контроллер:

    А теперь тот же контроллер с Inertia:

    Мы используем метод render inertia: .... Первым аргументом мы указываем имя компонента на фронтенде (обычно путь к файлу), а в props передаем данные. Обратите внимание: мы не создаем API-сериализаторы. Мы просто отдаем данные, необходимые конкретно этой странице.

    Фронтенд: React или Vue

    На стороне клиента структура папок обычно выглядит так:

    * app/javascript/pages/ — здесь лежат компоненты-страницы, соответствующие действиям контроллеров. * app/javascript/components/ — переиспользуемые UI-компоненты (кнопки, формы).

    Давайте посмотрим, как выглядит компонент Events/Show на React:

    Заметьте, здесь нет useEffect, нет fetch, нет состояний загрузки (isLoading). Данные event уже доступны в момент рендеринга, как если бы это был серверный шаблон.

    Маршрутизация: Rails остается главным

    Одна из самых частых ошибок новичков при переходе на SPA — попытка использовать react-router или vue-router. В Inertia маршрутизация остается на стороне сервера.

    Ваш файл config/routes.rb по-прежнему определяет все URL приложения:

    Чтобы создать ссылку на фронтенде, вы используете компонент Link, предоставляемый Inertia, но URL вы указываете тот, который определен в Rails:

    Это избавляет от дублирования логики маршрутов между клиентом и сервером.

    Общие данные (Shared Data)

    В классическом Rails у нас есть current_user или флеш-сообщения (flash[:notice]), которые доступны в любом шаблоне. Inertia решает эту задачу через механизм Shared Data.

    Вы можете настроить middleware Inertia так, чтобы определенные данные передавались с каждым ответом автоматически.

    Пример настройки в app/controllers/application_controller.rb (или в специальном инициализаторе):

    Теперь в любом React-компоненте вы можете получить доступ к пользователю или уведомлениям через пропсы, не передавая их явно в каждом контроллере.

    Формы и мутации данных

    Inertia предоставляет удобный хук useForm (для React) или объект формы (для Vue), который упрощает отправку данных обратно на сервер.

    Вам не нужно вручную обрабатывать ошибки валидации. Если Rails вернет код 422 и JSON с ошибками, Inertia автоматически заполнит объект errors, и вы сможете сразу показать их пользователю.

    Inertia vs Hotwire: Что выбрать?

    Теперь, когда мы изучили оба подхода, возникает закономерный вопрос: что использовать?

    | Характеристика | Hotwire (Turbo + Stimulus) | InertiaJS (React/Vue) | | :--- | :--- | :--- | | Язык | Преимущественно Ruby (HTML) | Ruby + JavaScript | | Сложность | Низкая | Средняя | | Рендеринг | Серверный (HTML) | Клиентский (DOM) | | Состояние | Хранится в HTML/URL | Хранится в JS-переменных | | Экосистема | Rails-специфичная | Огромная (React/Vue npm) | | Идеально для | Блоги, админки, CRUD-приложения | Сложные дашборды, редакторы, интерактивные карты |

    Hotwire должен быть вашим выбором по умолчанию. Он проще, быстрее в разработке и требует меньше кода. Используйте Inertia, когда интерактивность интерфейса становится настолько сложной, что управление ею через Stimulus превращается в «лапшу» из кода, или когда вам нужны готовые сложные компоненты из мира React (например, календарь, график или редактор текста).

    Заключение

    InertiaJS — это мост, который позволяет Rails-разработчикам использовать современные фронтенд-технологии без боли создания API. Вы сохраняете монолитную архитектуру, централизованную маршрутизацию и контроллеры, но получаете отзывчивый интерфейс SPA.

    В этом уроке мы разобрали теоретическую базу и настройку. Мы узнали, как данные перетекают из контроллеров в компоненты и как работает навигация. Это завершает наш обзор архитектурных подходов.

    Теперь у вас в арсенале есть два мощных инструмента: Hotwire для легких и быстрых интерфейсов, и Inertia для насыщенных клиентских приложений. Выбор инструмента зависит от задачи, и настоящий мастер Rails умеет сочетать их или выбирать наиболее подходящий для конкретного проекта.

    4. Сравнение подходов: выбор между Server-Side Rendering и клиентскими компонентами

    Сравнение подходов: выбор между Server-Side Rendering и клиентскими компонентами

    Мы подошли к экватору нашего курса. Позади остались модули, посвященные классическому Rails-монолиту, магии Hotwire и мощи InertiaJS. Теперь в вашем арсенале есть два диаметрально противоположных, но одинаково эффективных инструмента для создания современных веб-приложений.

    Однако наличие выбора порождает проблему выбора. Когда стоит использовать Turbo и Stimulus, а когда лучше подключить React или Vue через Inertia? Можно ли их смешивать? Какой подход лучше для SEO, а какой — для сложных интерактивных дашбордов?

    В этой статье мы проведем детальное сравнение подходов Server-Side Rendering (SSR) в исполнении Hotwire и Client-Side Rendering (CSR) (с гибридным подходом) в исполнении InertiaJS. Мы разберем критерии, которые помогут вам принять архитектурно верное решение для вашего следующего проекта.

    Фундаментальное различие: HTML против JSON

    Чтобы сделать правильный выбор, нужно вернуться к основам и понять, что именно передается по сети (over the wire) в каждом из случаев.

    Hotwire: HTML как источник истины

    В экосистеме Hotwire сервер (Rails) остается главным мозгом приложения. Он не только обрабатывает данные, но и решает, как они должны выглядеть. Сервер генерирует готовый HTML-код, который браузер просто вставляет в DOM-дерево.

    !Hotwire отправляет готовые HTML-фрагменты, которые браузер сразу отображает.

    Преимущества этого подхода:

  • Единая кодовая база: Логика отображения находится там же, где и бизнес-логика — в шаблонах Rails (.erb).
  • Скорость первой отрисовки (FCP): Браузер получает готовый контент сразу. Ему не нужно ждать загрузки JavaScript-бандла, его парсинга и выполнения, чтобы показать текст пользователю.
  • Простота: Вам не нужно думать о синхронизации состояния между клиентом и сервером. Состояние хранится в HTML или в базе данных.
  • InertiaJS: Данные отдельно, мухи отдельно

    InertiaJS использует гибридный подход. При первой загрузке сервер отдает HTML (для инициализации), но при последующей навигации сервер возвращает чистый JSON. Клиентский фреймворк (React/Vue) принимает этот JSON и перерисовывает компоненты.

    !InertiaJS отправляет сырые данные в формате JSON, а рендерингом занимается JavaScript на клиенте.

    Преимущества этого подхода:

  • Богатый UI: Вы получаете доступ ко всей экосистеме React/Vue. Календари, сложные таблицы, drag-and-drop интерфейсы — все это проще реализовать на компонентных фреймворках.
  • Ощущение нативного приложения: Интерфейс может реагировать мгновенно (Optimistic UI), даже если сервер еще не ответил.
  • Разделение ответственности: Фронтенд-разработчики могут работать с привычными им инструментами, не погружаясь глубоко в ERB-шаблоны.
  • Критерии выбора

    Давайте разберем конкретные сценарии и метрики, по которым стоит оценивать эти технологии.

    1. Сложность интерактивности

    Это самый важный критерий. Задайте себе вопрос: «Насколько сложным является состояние моего интерфейса?»

    * Низкая/Средняя сложность (Hotwire): Если ваше приложение — это классический CRUD (Create, Read, Update, Delete), блог, новостной сайт, админ-панель или интернет-магазин, Hotwire будет идеальным выбором. Turbo Frames позволят обновлять части страницы, а Stimulus добавит необходимые «украшения» (выпадающие меню, модальные окна). * Высокая сложность (InertiaJS): Если вы строите графический редактор, сложный канбан-доску (как Trello), систему аналитики с интерактивными графиками или музыкальный плеер, который не должен прерываться при навигации — выбирайте Inertia. Управлять сложным состоянием (например, перетаскиванием карточек между колонками с валидацией на лету) через Stimulus и HTML-атрибуты будет больно и неудобно.

    2. Команда и навыки

    Технологии не существуют в вакууме. Их используют люди.

    * Ruby-центричная команда: Если ваша команда состоит из сильных бэкендеров, которые любят Ruby и терпят JavaScript только по необходимости, Hotwire позволит им быть максимально продуктивными. Им не нужно учить хуки React или жизненный цикл Vue. * Смешанная команда: Если у вас есть фронтенд-разработчики, привыкшие к React, заставлять их писать на Stimulus и ERB может быть контрпродуктивно. Inertia позволит им писать на любимом фреймворке, при этом не требуя от бэкендеров создания сложного REST/GraphQL API.

    3. Производительность и SEO

    Здесь есть нюансы, которые часто упускают из виду.

    * SEO (Поисковая оптимизация): Hotwire выигрывает «из коробки». Поскольку сервер отдает чистый HTML, поисковые роботы видят контент сразу. InertiaJS (как и любые SPA) требует настройки Server-Side Rendering (SSR) на стороне Node.js для идеального SEO, что усложняет инфраструктуру. * Время загрузки: Hotwire-приложения обычно легче. Вы не тянете огромные бандлы React/Vue на клиент. Однако, если приложение очень интерактивное, постоянные запросы HTML к серверу могут создавать ощущение «задержки» (network latency), в то время как SPA может обработать действие мгновенно на клиенте.

    Сравнительная таблица

    | Характеристика | Hotwire (Turbo + Stimulus) | InertiaJS (React/Vue) | | :--- | :--- | :--- | | Тип рендеринга | Server-Side (HTML) | Client-Side (DOM) | | Язык шаблонов | ERB / Haml / Slim | JSX / Vue Templates | | Управление состоянием | В URL и HTML-атрибутах | В JS-переменных (Store) | | Сложность настройки | Низкая (встроено в Rails) | Средняя (требует Node.js/Vite) | | Экосистема библиотек | Ограничена (Stimulus components) | Огромная (npm: React/Vue) | | API | Не требуется | Не требуется (использует Props) | | Мобильные приложения | Turbo Native (гибридные) | Capacitor / WebView |

    Гибридный подход: Можно ли совмещать?

    Частый вопрос: «Могу ли я использовать Hotwire для всего сайта, а Inertia только для одной сложной страницы?»

    Технически — да. Вы можете подключить Inertia и рендерить компоненты только в определенных контроллерах. Однако, на практике это часто приводит к архитектурному «Франкенштейну»:

  • Вам придется поддерживать два пайплайна сборки ассетов.
  • Навигация между страницами Hotwire и Inertia будет вызывать полную перезагрузку страницы (full page reload), теряя преимущества SPA.
  • Разработчикам придется переключать контекст между ERB и React-компонентами.
  • Рекомендация: Старайтесь придерживаться одного подхода в рамках одного приложения. Если у вас есть изолированная часть с очень сложной логикой (например, конструктор отчетов), рассмотрите возможность выноса её в отдельное мини-приложение или используйте «острова» React внутри Hotwire (через специальные гемы вроде react-rails, но это уже выходит за рамки Inertia).

    Реальные сценарии принятия решений

    Давайте рассмотрим три примера, чтобы закрепить материал.

    Сценарий А: Корпоративная CRM-система

    Задача: Много таблиц, форм, списков клиентов. Нужна надежность и быстрота разработки. Решение: Hotwire. Большинство действий — это стандартный CRUD. Turbo Frames отлично справятся с редактированием строк в таблицах без перезагрузки.

    Сценарий Б: Платформа для онлайн-обучения (LMS)

    Задача: Видео-плеер, тесты с мгновенной проверкой, интерактивные упражнения, чат. Решение: InertiaJS. Тесты и упражнения требуют сложного состояния на клиенте (прогресс, таймеры, drag-and-drop ответов). Делать это на Stimulus будет сложно.

    Сценарий В: Личный кабинет пользователя

    Задача: Настройки профиля, смена пароля, история заказов. Решение: Hotwire. Это простые формы. Подключать React ради трех полей ввода — избыточно.

    Заключение

    Выбор между Hotwire и InertiaJS — это не выбор между «плохим» и «хорошим». Это выбор между простотой и контролем.

    * Выбирайте Hotwire, если хотите максимальной скорости разработки, любите Ruby и ваше приложение укладывается в стандартные паттерны веба. * Выбирайте InertiaJS, если вам нужен полный контроль над поведением интерфейса, вы хотите использовать мощь React/Vue, но не хотите страдать от создания API.

    В современном Rails нет неправильного пути. Оба эти подхода позволяют создавать великолепные монолиты, которые легко поддерживать и масштабировать. Главное — понимать потребности вашего проекта и возможности вашей команды.

    На этом мы завершаем теоретический блок сравнения. В следующих уроках мы перейдем к практике и реализуем одну и ту же фичу двумя способами, чтобы вы могли почувствовать разницу кончиками пальцев.

    5. Лучшие практики: тестирование, оптимизация производительности и деплой приложений

    Лучшие практики: тестирование, оптимизация производительности и деплой приложений

    Мы прошли долгий путь от создания нового Rails-приложения до реализации сложных интерфейсов с помощью Hotwire и InertiaJS. Теперь перед нами стоит задача, отличающая любительский проект от профессионального продукта: как сделать так, чтобы приложение работало стабильно, быстро и легко обновлялось.

    В этой статье мы рассмотрим три кита, на которых держится «Величественный Монолит» в продакшене: стратегии тестирования гибридных приложений, тонкости оптимизации производительности и современный подход к деплою с использованием инструмента Kamal.

    Тестирование: уверенность в каждом коммите

    В мире Rails тестирование — это религия. Однако появление Hotwire и InertiaJS меняет подход к написанию тестов. Классических контроллер-тестов и unit-тестов моделей уже недостаточно, так как значительная часть логики переехала в интерактивное взаимодействие в браузере.

    Пирамида тестирования в современном Rails

  • Unit Tests (Модели/Jobs): Здесь ничего не меняется. Вы тестируете бизнес-логику, валидации и работу с БД. Это фундамент.
  • System Tests (E2E): Это самый важный слой для Hotwire и Inertia. Поскольку логика размазана между сервером и клиентом, только запуск реального браузера (обычно Headless Chrome) может гарантировать, что кнопка действительно открывает модальное окно.
  • Особенности тестирования Hotwire

    При использовании Turbo Frames и Streams важно проверять не только то, что сервер вернул код 200, но и то, что DOM действительно обновился.

    Для этого мы используем System Tests (на базе Capybara). Пример теста для чата на Hotwire:

    Особенности тестирования InertiaJS

    С Inertia у вас есть два пути, и лучше использовать оба:

  • Тестирование контроллеров (Request Specs): Вы проверяете, что контроллер возвращает правильный компонент и правильные данные (props). Рендерить HTML здесь не нужно.
  • Тестирование компонентов (Frontend): Используйте Jest или Vitest + React Testing Library для проверки логики внутри JS-компонентов изолированно от Rails.
  • Оптимизация производительности

    Монолит может быть быстрым, если вы умеете готовить данные. Главный враг производительности в Rails — это база данных, а главный враг в SPA — размер JavaScript-бандла.

    Проблема N+1 запросов

    Это классика. Если вы передаете в Inertia список из 50 событий, и у каждого события есть автор, Rails по умолчанию сделает 1 запрос для событий и 50 запросов для авторов.

    Решение: Всегда используйте жадную загрузку (eager loading) при подготовке данных для пропсов или шаблонов.

    Partial Reloads и Lazy Loading в Inertia

    InertiaJS передает данные в виде JSON, встроенного в HTML-страницу. Если у вас есть тяжелые данные (например, сложная статистика), которые нужны не сразу, они могут замедлить первую отрисовку.

    Используйте Lazy Loading (ленивую загрузку). Данные не будут загружены при первом визите, а подгрузятся только по явному запросу.

    В контроллере:

    На клиенте (React):

    Кэширование в Hotwire

    Rails имеет мощнейший механизм кэширования фрагментов (Russian Doll Caching). С Turbo Frames это работает идеально: вы можете кэшировать содержимое фрейма независимо от остальной страницы.

    Деплой: Эра Kamal

    Долгое время стандартом деплоя Rails был Capistrano, затем Heroku. Сейчас мы входим в эру контейнеров. Современный стандарт деплоя Rails-приложений — это инструмент Kamal (ранее MRKS), созданный командой Basecamp.

    !Архитектура деплоя Kamal: от локального кода до контейнеров на сервере

    Почему Kamal?

    Kamal позволяет деплоить приложение на любой Linux-сервер (AWS, DigitalOcean, Hetzner или даже старый компьютер в подвале) с той же легкостью, что и на Heroku, но без лишних затрат.

    Как это работает:

  • Вы описываете конфигурацию в файле config/deploy.yml.
  • Kamal собирает Docker-образ вашего приложения локально или в CI.
  • Загружает образ в реестр (Docker Hub, GitHub Packages).
  • Подключается к вашему серверу по SSH.
  • Запускает новый контейнер и плавно переключает трафик через прокси Traefik (Zero Downtime Deploy).
  • Пример конфигурации (deploy.yml)

    Всего одна команда kamal deploy выполняет весь процесс от сборки до запуска.

    CI/CD: Автоматизация процессов

    Ручной деплой — это риск. Лучшая практика — настроить Continuous Integration / Continuous Delivery.

    Типичный пайплайн для Rails-проекта на GitHub Actions выглядит так:

  • Push в ветку main.
  • Запуск тестов: Поднимается PostgreSQL, запускается bin/rails test:system.
  • Линтинг: Rubocop проверяет стиль кода.
  • Сборка и Деплой: Если тесты прошли, GitHub Actions запускает kamal deploy.
  • Это гарантирует, что сломанный код никогда не попадет в продакшен.

    Заключение курса

    Мы завершаем наш курс по современной веб-разработке на Ruby on Rails. Мы увидели, что Rails жив как никогда. Концепция «Величественного Монолита», усиленная технологиями Hotwire и InertiaJS, позволяет небольшим командам создавать продукты мирового уровня.

    * Используйте Hotwire для максимальной скорости разработки и SEO. * Используйте InertiaJS для сложных, насыщенных интерфейсов, где нужен React/Vue. * Тестируйте систему целиком, оптимизируйте запросы к БД и деплойте с помощью контейнеров.

    Теперь у вас есть все инструменты, чтобы превратить вашу идею в работающий продукт. Удачи в коде!