Service objects are Plain Old Ruby Objects used to extract code from a part of the application where it doesn’t really belong and isolate it in its own, testable file.

They often look like:

class ServiceObject
  def initialize(param1, param2)
    # set params
  end
  
  def do_something
  # do something
  end
  
  private
  
  def private_methods
    #
  end
end

They can then be called like this:

class SomeController < ApplicationController
  service_object = ServiceObject.new(params[:a], params[:b])

  if service_object.do_something
    # Happy path
  else
    # Sad path
  end
end

This simplifies your controller and makes it much more understandable. It also separates the controller concerns (responding to requests and returning html/json/etc) from the service object concerns.

You will also see service objects that are structured like this:

class ServiceObject
  def self.call(params)
    # Do everything here
  end
end

Which are then called like this:

class SomeController < ApplicationController
  if ServiceObject.call(params[:a])
    # Happy path
  else
    # Sad path
  end
end

Reddit’s thoughts on Ruby Service Objects