Maksym Prokopov personal blog
Idea is a something worth sharing

Legacy Rails project and modern Assets Pipeline

22.05.2025

One of the projects I’ve started a long-long time ago still powers the business. It was quite a journey starting from Rails 2, than Rails 3 and so on up until currently Rails 7 with plans to bump to Rails 8.

The project has live updates with Server Sent Events and a sidecar microservice to keep the connections and push updates. Quite similar to what DHH have done with ActiveCable, but based on different stack.

Here is a list of technologies, thanks to browser backward compatibility, still works:

The Javascript and SCSS got bundled together using sprockets gem.

It’s definitely time to move on.

But, rewriting the whole project would have been a mistake! https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/

The current state of the art in Rails community and in version 8 is

The scale of the problem with the transition towards the new stack without major rewrite was clear after the whole was spent trying to play legacy stuff like jQuery nicely with importmap.

Woah! Somebody should have told me, there is fundamental incompatibility with ES6 modules style and legacy “no style” Javascript.

Long story short, the proper combination is to ADD importmap gem to the existing codebase, WITHOUT trying to convert all existing scripts in one shot.

Only after adding importmap + stimulus + turbo it’s time to refactor small pieces one-by-one, carefully removing the old Javascript code.

It worth noting, you might have to rename existing application.js to app.js to avoid clashes in importmaps vs sprockets. Other significant aspect, is to turn off Turbo for the entire site and enable it only on certain pieces.

import { Application } from "@hotwired/stimulus"
import "@hotwired/turbo-rails"

// gradually enable turbo
Turbo.session.drive = false

and activate somewhere

<div data-turbo="true">
...
</div>

So far, the difference in complexity is huge! The same functionality is by far easier to do with turbo-stream elements coming from backend, than juggling data with calls to a separate API Engine (!) with JSON output.

The rewrite is still in progress, but the foot is definitely in the door.

Other gotchas

turbo-frame vs turbo-stream

The difficulty is, the both tags intendend to replace parts of the page dynamically, but it’s not immediately clear what tag to use when.

Here is my rule of thumb.

Use turbo-frame for updating single parts and splitting a parts of a page into deferred loading.

Use turbo-stream to update parts of the page from ActiveCable or when you need to updates several parts of the page at the same time.

Nice use case, you could add the whole controller template as “turbo-stream” type. In this example it’s a contents of show.turvbo-stream.erb file

<%= turbo_stream.update :employeeDetails do %>
    <%= render 'employee', employee: @employee %>
<% end %>

<%= turbo_stream.update :clientDetails do %>
    <%= render 'client', client: @client %>
<% end %>

<%= turbo_stream.update :lastEmployeeTickets do %>
    <div class="new_ticket-header"><%= t 'Last5EmployeeTickets' %></div>
    <%= render 'tickets', tickets: @employee_tickets %>
<% end %>

<%= turbo_stream.update :lastClientTickets do %>
    <div class="new_ticket-header"><%= t 'OpenClientTickets', name: @client.name %></div>
    <%= render 'tickets', tickets: @client_open_tickets %>
<% end %>

<%= turbo_stream.update :subscribers do %>
    <%= render 'subscribers', subscribers: @subscribers %>
<% end %>

Most valuable experience on how to connect and use Stimulus was from reading https://once.com/writebook source code.

Ruby on Rails хозяйке на заметку: менеджер локальных сайтов Pow

12.04.2011

Чрезвычайно удобной оказалась возможность работы с несколькими сайтами на базе RoR (по факту на Rack), которую предоставляет утилита Pow.

Вкратце, если у вас достаточно много сайтов разработке, утилита предоставляет хук в DNS зону dev и позволяет обращаться к вашим сайтам по url вида http://myapp.dev , http://myapp2.dev, а также добавляет правило в фаерволе, которое заворачивает обращения к self с порта 80 на внутренний порт утилиты.

Сам Pow состоит из двух частей — DNS responder и проксирующего web server. Реализовано все счастье на Node.js.

Очень интересна реализация зоны .dev, в mac os в каталоге /etc/resolver/ добавляется файл dev такого вида:

nameserver 127.0.0.1 port 20560

что перенаправляет все обращения xxx.dev на соответствующее приложение

 

Утилита поддерживает работу с RVM, что позволяет упражняться с различными версиями руби.

Для поддержки в rails 2 через Pow можно воспользоваться таким хаком, создаем в корне приложениея config.ru, где прописываем

Деинсталляция также проста:

curl get.pow.cx/uninstall.sh | sh
# Rails.root/config.ru
require "./config/environment"
run ActionController::Dispatcher.new

Утилита что-то наподобие denwer для php.

 

Cucumber говорит по-русски

26.12.2009

Для тех ребят, которые увлекаются канбанами, TDD и прочими agile системами разработки следующим шагом является приобщение к BDD.

По-сути Cucumber представляет собой интеграционные тесты при помощи webrat или других высокоуровневых библиотек для эмуляции работы браузера, открывания странц, нажимания на кнопки и кликания по ссылкам.

Теперь с cucumber жить еще проще, рассказывать по-русски можно при помощи тега

@language ru

Типичный сценарий:

# language: ru
Функционал: отчеты по времени
  Чтобы получить понятие о стоимости часа для конкретной компании
  Я как руководитель
  Хочу иметь возможность просматривать отчеты по временным затратам на каждую компанию

Предыстория:
  Допустим существует клиент, админ и сотрудник клиента

Сценарий: просмотр суммарно затраченного времени за текущий месяц
  Допустим админ авторизован
  И открывет страницу отчетов
  То видит список клиентов с затраченным временем за последний месяц
cucumber тесты по-русски

cucumber тесты по-русски