class ServiceObject::Base

Service object base class which provides interfaces to controllers so that they can access the result of service processing and its errors if any. Uses ServiceObject::Errors as the error container.

Attributes

errors[R]

@return [ServiceObject::Errors] Errors object of the current service

Public Class Methods

new(*args) click to toggle source
# File lib/service_object/base.rb, line 11
def initialize(*args)
  @result = true
  @errors = Errors.new
end
transaction(&block) click to toggle source

Shorthand for ActiveRecord::Base.transaction

# File lib/service_object/base.rb, line 100
def transaction(&block)
  ActiveRecord::Base.transaction(&block)
end

Public Instance Methods

error_messages() click to toggle source

Error messages of the service process so far @return [Array] Array of error messages

# File lib/service_object/base.rb, line 80
def error_messages
  @errors.full_messages
end
execute()
Alias for: run
executed_successfully?()
Alias for: result
ran_successfully?()
Alias for: result
result() click to toggle source

Check if the service process is going well or not so far @return [true, false]

# File lib/service_object/base.rb, line 86
def result
  @result && @errors.empty?
end
run() { |self| ... } click to toggle source

This runs your logic without exposing unessential processes to your controllers. @return [true, false]

Examples: # Controller

def some_action_on_book
  service = CreateMyBookService.new(params[:isbn])
  service.run do |s|
    s.get_info_from_isbn_api
    s.get_availability_with_library
    s.save_my_book
  end
  if service.result
    render json: { result: 'success', message: 'Successfully saved the book data' }
  else
    render json: { result: 'failure', messages: service.error_messages }
  end
end

# Service class CreateMyBookService < ServiceObject::Base

def initialize(isbn)
  super # This is necessary
  @isbn = isbn
  @book_info = nil
  @my_book = MyBook.new # ActiveRecord Model
  @isbn_api = IsbnApi.new(@isbn) # Non-AR Model
  @library_api = LibraryApi.new # Non-AR Model
end

def get_info_from_isbn_api
  @book_info = @isbn_api.get_all_info
end

def get_availability_with_library
  @availability = @library_api.get_availability(@isbn)
rescue Net::HTTPError => e
  # You can re-throw you own error, too.
  raise YourError, 'Failed to get availability from library'
end

def save_my_book
  @my_book.update!(
      available: @availability,
      name: @book_info.title,
      author: @book_info.author,
      isbn: @isbn
 )
end

end

# File lib/service_object/base.rb, line 67
def run
  before_run
  yield self
  after_run
  @result
rescue => e
  process_exception(e)
  @result = false
end
Also aliased as: execute
transaction(&block) click to toggle source

Shorthand for ActiveRecord::Base.transaction

# File lib/service_object/base.rb, line 93
def transaction(&block)
  self.class.transaction(&block)
end

Private Instance Methods

after_run() click to toggle source

Override this method when there are other post-processes that you don't want to show in controller.

# File lib/service_object/base.rb, line 111
def after_run; end
before_run() click to toggle source

Override this method when there are other pre-processes that you don't want to show in controller.

# File lib/service_object/base.rb, line 108
def before_run; end
flattened_active_model_error(active_model) click to toggle source

Change activemodel errors into a string to be added to service errors @param active_model [ActiveModel] ActiveModel Object

whose error messages are to be flattened

@return [String] Flattened string error message

# File lib/service_object/base.rb, line 125
def flattened_active_model_error(active_model)
  "#{active_model.class}: #{active_model.errors.full_messages.join(', ')}"
end
process_exception(e) click to toggle source

@param e [StandardError] This puts all StandardError encountered into @errors, which will be available through error_messages. If you want to specify special behaviors for each error type such as some rollback process or error logging, please override this method. (See README.md Sample 2.)

# File lib/service_object/base.rb, line 117
def process_exception(e)
  @errors.add "#{e.class}: #{e.message}"
end