I have a bulk update process which updates a Product's (has_many) Subscription and is called in several places, so I refactor it into a service.
In each place where calls this process still has its own special pre-process: like adding counter, etc. and some subscriptions :update can be skipped if it will be destroyed. So I send block to it:
# subscriptions_params is an array containing permitted parameters from controller
module SavingService
def self.call!(product, subscriptions_params)
subscriptions_params.each do |params|
subscription = product.subscriptions.find(params[:id])
next if block_given && !yield(subscription, params)
subscription.update!(params)
end
product.update_something!
end
end
# It can work well
SavingService.call!(product, subscriptions_params)
# I can add some special process in the block
SavingService.call!(product, subscriptions_params) do |subscription, params|
if params[:checked]
subscription.counter += 1
true
else
subscription.destroy!
false
end
end
However, I need to explicitly return true or false to do "next", it will be hard to maintain after... like 6 months. Every developer will be confused that why it needs to return true, false explicitly. Is there any way I can call next from the block? or don't need to use the block?
I know I can solve this problem by applying Template Pattern: make an abstract class containing the process and inherit it to overwrite each private method:
class SavingService
def call!
pre_process
process
post_process
end
private
def pre_process; end
def process; end
def post_process; end
end
But the different parts of each place calling the process are very small, just 1~3 lines. I don't want to create so many classes for such tiny differences, so I choosed to use block first.
Aucun commentaire:
Enregistrer un commentaire