Service Object, Interactor и Command-подход: кто во что обернут

Сервисные объекты в Ruby on Rails помогают вынести бизнес-логику из контроллеров, делая код чище и тестируемее. В статье разбираем три популярных подхода — Service Object, Interactor и Command — с примерами реализации и рекомендациями по выбору для разных сценариев. Узнайте, как правильно организовать сервисный слой в вашем Rails-приложении, чтобы упростить поддержку и масштабирование.


Когда в контроллере стало слишком душно — на сцену выходит сервисный слой.
Но кого выбрать: простой Service Object, паттерн Command или gem interactor?

🧱 Service Object

Класс с одним публичным методом call, который выполняет бизнес-логику. Простой и честный:

class RegisterUser
  def initialize(params)
    @params = params
  end

  def call
    User.create!(@params)
  end
end

Вызов: RegisterUser.new(params).call


🧙‍♂️ Interactor

Если нужен context, fail!, и цепочка вызовов — поможет gem interactor.

class RegisterUser
  include Interactor

  def call
    user = User.create(context.params)
    context.fail!(error: "bad data") unless user.persisted?
    context.user = user
  end
end

Вызов: RegisterUser.call(params: ...) В цепочке: Organizer.call(...)


🧾 Command-подход

Похож на Service, но делает упор на явность, сигнатуру и инварианты:

class RegisterUser < BaseCommand
  def call
    validate_input!
    create_user!
  end
end

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


🚦 Когда использовать

Сценарий Подход
Быстро обернуть бизнес-логику Service Object
Хочется fail! и цепочек Interactor
Инфраструктура с логгерами, events Command-подход

💬 Вывод

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

🗓 Дата публикации: 07.05.2025, но это не точно...

Ruby on Rails Service Object Interactor Command бизнес-логика сервисный слой