Build Robust & Production Quality Applications - Lesson 8: Beyond MVC - Service Objects
13 Jul 2015Service Objects
Just like we can extract domain logic into domain objects, we can extract business level logic into service objects. Currently, the below process is modeling the Credit Deduction Business Process. Let's extract that into a Service Object called CreditDeduction.
#apps/controllers/todos_controller.rb
def create
@todo = Todo.new(params[:todo)]
credit = Credit.new(current_user)
if @todo.save_with_tags
if UserLevelPoicy.new(ccurent_user).premium?
credit = credit - 1
else
credit = credit - 2
end
credit.save
if credit.depleted? < 0
AppMailer.notify.insufficient_funds
elsif credit.low_balance?
AppMailer.notify_low_balance
end
redirect_to root_path
else
render :new
end
Create the Service Policy called CreditDeduction
#app/services/credit_deduction.rb
Class CreditDeduction
end
Extract business process related Code
#app/services/credit_deduction.rb
Class CreditDeduction
attr_accessor :user
def initialize(user)
@user = user
end
def deduct_credit
if UserLevelPoicy.new(ccurent_user).premium?
credit = credit - 1
else
credit = credit - 2
end
credit.save
if credit.depleted? < 0
AppMailer.notify.insufficient_funds
elsif credit.low_balance?
AppMailer.notify_low_balance
end
end
end
Update the TodoController
#apps/controllers/todos_controller
def create
@todo = Todo.new(params[:todo)]
credit = Credit.new(current_user)
if @todo.save_with_tags
CreditDeduction.new(credit, current_user).deduct_credit
redirect_to root_path
else
render :new
end
end
end
Move instatiating a new Credit Object to your Service Policy
#app/services/credit_deduction.rb
Class CreditDeduction
attr_accessor :credit, :user
def initialize(credit, user)
@credit = Credit.new(user)
@user = user
end
def deduct_credit
if UserLevelPoicy.new(ccurent_user).premium?
credit = credit - 1
else
credit = credit - 2
end
credit.save
if credit.depleted? < 0
AppMailer.notify.insufficient_funds
elsif credit.low_balance?
AppMailer.notify_low_balance
end
end
end
#apps/controllers/todos_controller
def create
@todo = Todo.new(params[:todo)]
if @todo.save_with_tags
CreditDeduction.new(current_user).deduct_credit
redirect_to root_path
else
render :new
end
end
end