Восемь лет писал на Laravel, второй месяц на Rails 7.0, Ruby только что обновили до 3.2. Многое нравится: миграции, консоль, Active Record почти как Eloquent, только приятнее. Но две вещи ломают голову. Нет контейнера зависимостей, классы берутся просто из воздуха, и непонятно, как их подменять в тестах. И нет типов: в PHP 8 я к ним привык, а тут метод принимает что угодно, и узнаёшь об этом в рантайме. Это надо просто принять или есть практики?
Контейнера нет, и в большинстве проектов он не нужен. Классы грузит Zeitwerk по имени файла, а зависимости, которые хочется подменять, передают явно, со значением по умолчанию:
class Checkout
def initialize(gateway: PaymentGateway.new, mailer: OrderMailer)
@gateway = gateway
@mailer = mailer
end
def call(order)
@gateway.charge(order.total, order.payment_method_id)
@mailer.with(order: order).paid.deliver_later
end
end
# в тесте
Checkout.new(gateway: FakeGateway.new).call(order)
В коде пишешь Checkout.new.call(order), в тесте передаёшь фейк. Для внешних HTTP-вызовов ещё проще взять WebMock, тогда и подменять ничего не надо. А про типы честно: их нет, и это цена. Компенсируют тестами, маленькими методами и понятными именами.
Мне с типами помогла открытая rails console: что метод принимает и возвращает, проверяешь там за пять секунд
Типы, кстати, есть, просто рядом с кодом: RBS идёт с Ruby начиная с 3.0, есть ещё Sorbet. В Rails-проектах их, правда, держат редко