At Your Service…An Overview of Ruby Service Objects
I am currently building an application whose Rails API backend fetches tweets from the Twitter API and stores information from those tweets in a non-persistent API. In order to keep my controller as RESTful as possible, I decided to implement Service Objects. Service Objects are useful in keeping models and controllers thin and handling the business logic that would otherwise be in those models or controllers.
Service Objects are Plain Old Ruby Objects (PORO) which means that they are just classes that do not inherit or extend any other classes. Because service objects are responsible for an application’s business logic, looking at an application’s service object should tell you what the application is doing. For example, in my application I have two services — a Tweets Processor and a Sentiment Analyzer. As you can guess from the names, my Tweets Processor fetches tweets from the Twitter API, parses the data and then creates new instances of my Tweet class to be held in my API. My Sentiment Analyzer applies the sentimental Ruby gem to the tweets that I am getting back, analyzes the content and provides a positive, neutral or negative score.
In order to use those methods, an application would then instantiate them in its controller actions, tell them to do x, y and z and respond back to the user. So in my application, my controller calls these service objects when there is a post request to create new instances of my Tweet class so they can be added to my API.
How To Create a Service Object
Within your app folder, your services should go in their own services folder.
After you create a file for your service and define a plain Ruby class, you use an initialize method to create the needed instance variables upon the object being instantiated. In my case, I am passing in a search term that will be used in my Twitter API request. I then have put all the methods I need to hit the Twitter API, parse the tweets and create new instances of my Tweet object that will be added to my API.
My controller then is able to access the methods in this service by instantiating a new Tweets Processor instance when there is a post request to create new Tweets based on a new search term.
This keeps my controller super dry and thin by having all of the methods in a separate file and accessing them by instantiating my service in the controller.