Ruby on Rails provides everything you need to quickly create your application, but as your application starts to develop, you will experience situations where models and controllers swell, in branches, and difficult to control when dealing with complex business and logic, including functions that require us to interact with many different Models, not targeting a specific model.
Service Object is one of the solutions to this problem. It was born as a container for various business logic in which the processing object did not belong to any model.
The benefit of Service Object is that it helps us to focus all of the functionality logic into a separate object without having to subdivide it into controllers and models as usual. We always call that object when we need it. Because the logic block is focused on one object, it will minimize the controller and model a lot, the code clean and the maintain process is also less strenuous in the future.
service object class
classes are a good choice if you want to save data to instance variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class ServiceObject def call(arg1, arg2, ...etc) new(arg1, arg2, ...etc).call end private def initialize(arg1, arg2, ...etc) @var = arg1 @var = arg2 ...etc end def call # Logic goes here end end |
service object module
If you don’t want to save data to instance variables, then a module is a lighter option
1 2 3 4 5 6 | module ServiceObject def perform(arg1, arg2, ...etc) # Logic goes here end end |
how to use the service object
Normally in Rails system services will be concentrated in the app / services directory . Depending on the specificity and complexity of the project, we can subdivide the services into many sub-categories. In this example, I will create a service object named CalculatorService:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | class CalculatorService def initialize(number_1, number_2, method = nil) @number_1 = number_1 @number_2 = number_2 @method = method end def perform case method when :addition addition when :subtraction subtraction when :multiplication multiplication when :division division else "You have not selected a calculation method" end end private attr_accessor :number_1, :number_2, :method def addition number_1 + number_2 end def subtraction number_1 - number_2 end def multiplication number_1 * number_2 end def division return "Denominator cann't be zero" if number_2.zero? (number_1 / number_2).to_f end end |
The CalculatorService class is initialized with the parameters number_1, number_2, method
and has methods of addition
, subtraction
, multiplication
, division
We can call the service object wherever and whenever we need to use it
1 2 3 | result = CalculatorService.new(5, 7, :addition).perform => 12 |
Note: if your service object is a module then you must include or extend it depending on your intended use.
summary
The article aims to share a bit of my knowledge and basic usage of Service Object, the article is still limited, thank you for reading.
References:
https://www.thegreatcodeadventure.com/service-objects-in-rails/ https://www.toptal.com/ruby-on-rails/rails-service-objects-tutorial https://blog.appsignal.com /2020/06/17/using-service-objects-in-ruby-on-rails.html