-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
The Service Object Pattern
Description
- Change Something / Return Nothing
- Perform a single unit of business logic
- File name describes the side effect
When to use it
- You have a single contained unit of business logic
- You need to execute a series of steps
- You want to initiate a side-effect
When not to use it (Anti-patterns)
- You have made all objects into Services - Everything is a Service (spoiler: it isn't)
- You are mixing querying and command pattern
- You have service objects that are actually multiple service objects (God Objects)
Before
class UsersController < ApplicationController
def create
user = User.new(user_params)
if user.save
UserMailer.sign_up.deliver_later
Subscription.create(status: "active", user:)
Analytics::UserSignUpEvent.track(user)
head 200
else
head 400
end
end
endAfter
class CreateUserService < ApplictionService
def initialize(user:)
@user = user
end
def call
User.transaction do
user.save
UserMailer.sign_up.deliver_later
Subscription.create(status: "active", user:)
Analytics::UserSignUpEvent.track(user)
end
true
rescue SubscriptionError, UserError => e
false
end
private
attr_reader :user
end
class UsersController < ApplicationController
def create
user = User.new(user_params)
service = CreateUserService.new(user:)
if service.call
head 200
else
head 400
end
end
endFuture
Result returning
class CreateUserService < ApplictionService
def initialize(user:)
@user = user
end
def call
User.transaction do
user.save
UserMailer.sign_up.deliver_later
Subscription.create(status: "active", user:)
Analytics::UserSignUpEvent.track(user)
end
Success.new(user, "User created")
rescue SubscriptionError, UserError => exception
Failure.new(exception)
end
private
attr_reader :user
end
class UsersController < ApplicationController
def create
user = User.new(user_params)
service = CreateUserService.new(user:)
service.call
if service.success?
render json: { error: service.message }
else
render json: { error: service.exception }
end
end
endMetadata
Metadata
Assignees
Labels
No labels