Сервисные объекты предназначены для вещей, которые не вписываются в обычную парадигму MVC.Обычно они предназначены для бизнес-логики, которая в противном случае сделала бы ваши модели или контроллеры слишком толстыми.Как правило, они не имеют состояния (которое содержится в модели) и выполняют такие вещи, как общение с API или другая бизнес-логика.Сервисные объекты позволяют сохранять ваши модели тонкими и сфокусированными, а каждый сервисный объект также тонок и ориентирован на выполнение одной вещи.
Rails Service Objects: полное руководство содержит примеры использования сервисных объектовуправлять взаимодействием с Twitter или инкапсулированием сложных транзакций базы данных, которые могут пересекаться с несколькими моделями.
Сервисные объекты в Ruby on Rails… и вы показывает создание сервисного объекта для управления процессом регистрации нового пользователя..
Блог EngineYard опубликовал Использование сервисов для поддержания чистоты ваших контроллеров Rails и DRY с примером сервисного объекта, который выполняет обработку кредитных карт.
Если выВ поисках источников Сервисные объекты в Rails помогут вам разработать чистый и поддерживаемый код.Вот как. относится к 2014 году, когда они появлялись на сцене.
Преимущество служб заключается в том, чтобы концентрировать основную логику приложения в отдельном объекте, а не разбрасывать его по контроллерам имодели.
Общей характеристикой всех сервисов является их жизненный цикл:
- прием ввода
- выполнение работы
- возврат результата
Если это звучит очень похоже на то, что делает функция, вы правы!Они даже рекомендуют использовать call
в качестве имени публичного метода в сервисе, как Proc .Вы можете думать об объектах службы как о способе именования и организации того, что в противном случае было бы большой подпрограммой.
Анатомия объекта службы Rails устраняет разницу между объектом службы и проблемой.Он охватывает преимущества, которые объект обслуживания имеет перед модулями.В нем подробно рассказывается о том, что делает хороший сервисный объект, включая ...
- Не сохранять состояние
- Использовать методы экземпляра, а не методы класса
- Должно быть очень мало открытых методов
- Параметры метода должны быть объектами-значениями, либо для работы, либо для использования в качестве ввода
- Методы должны возвращать объекты с богатым результатом, а не логические значения
- Зависимые сервисные объекты должны быть доступны через частные методы и создаваться либо в конструкторе, либо лениво
Например, если у вас есть приложение, которое подписывает пользователей на списки, которые могут быть тремя моделями:Пользователь, список, подписка.
class List
has_many :subscriptions
has_many :users, through: :subscriptions
end
class User
has_many :subscriptions
has_many :lists, through: :subscriptions
end
class Subscription
belongs_to :user
belongs_to :list
end
Процесс добавления и удаления пользователей в списки и из них достаточно прост с помощью базовых методов и ассоциаций create
и destroy
и, возможно, нескольких обратных вызовов.
Теперь ваш начальник хочет разработать сложный процесс подписки, который будет вести обширную регистрацию, отслеживать статистику, отправлять уведомления в Slack иTwitter, отправляет электронные письма, проводит обширные проверки ... теперь то, что было простым create
и destroy
, превращается в сложный рабочий процесс, связываясь с API и обновляя несколько моделей.
Вы можете написать все это как проблемы или модули,включите все эти вещи в эти три простые модели и напишите большие методы классов Subscription.register
и Subscription.remove
.Теперь ваши подписки могут чирикать и публиковать в Slack, проверять адреса электронной почты и выполнять проверку данных?Weird.Ваши модели теперь раздуты с кодом, не связанным с их основными функциями.
Вместо этого вы можете написать SubscriptionRegistration
и SubscriptionRemove
сервисные объекты.Они могут включать в себя возможность чирикать, хранить статистику, выполнять фоновые проверки и т. Д. (Или, скорее, использовать это в большем количестве служебных объектов).У каждого из них есть один публичный метод: SubscriptionRegistration.perform(user, list)
и SubscriptionRemove.perform(subscription)
.Пользователь, Список и Подписка не должны ничего знать об этом.Ваши модели остаются стройными и делают одно.И каждый из ваших сервисных объектов делает одно.
Что касается ваших конкретных вопросов ...
Откуда эта парадигма / тренд?
Насколько я могу судить, это следствие тенденции "толстая модель / тощий контроллер";вот как я к этому пришел.Хотя это хорошая идея, часто ваши модели становятся слишком толстыми.Даже с модулями и проблемами это становится слишком много, чтобы втиснуть в один класс.Другая бизнес-логика, которая обычно раздувает модель или контроллер, переходит в сервисные объекты.
Какой гем / плагин создает папку app / services?
Вы делаете.Все в app/
автоматически загружается в Rails 5.