Rails: How to respond with custom error messages in the ActiveRecord way without having a model

Rails: How to respond with custom error messages in the ActiveRecord way without having a model

Here you have a quick example:

Let’s begin with the service for that.
app/services/format_response_with_active_model_errors.rb

class FormatResponseWithActiveModelErrors
  extend ActiveModel::Naming

  def initialize
    @errors = ActiveModel::Errors.new(self)
  end

  def valid?
    errors.empty?
  end

  attr_reader :errors
  attr_accessor :response

  def add_error_message!(field_name:, message:)
    errors.add(field_name, message)
  end

  def read_attribute_for_validation(attr)
    send(attr)
  end

  # Needed when using the errors.full_messages method
  def self.human_attribute_name(attr, options = {})
    attr
  end

  # Needed for translations
  def self.lookup_ancestors
    [self]
  end
end

And we are going to use it within another service class
app/services/my_service.rb

class MyService
  def self.calculate_a_thing(params)
    response_with_errors = FormatResponseWithActiveModelErrors.new

    if condition_true?
      response_with_errors.add_error_message!(
        field_name: 'my_field_name',
        message: 'Custom error message'
      )
      return response_with_errors
    end

    if another_condition?
      response_with_errors.add_error_message!(
        field_name: 'my_field_name_2',
        message: 'Custom error message'
      )
      return response_with_errors
    end

    response_with_errors

  rescue StandardError => e
    logger.info '-------------'
    response_with_errors.add_error_message!(
      field_name: 'unexpected_exception',
      message: "An exception has ocurred when creating sessions/tokens for Opentok #{e.to_s}"
    )

    response_with_errors
  end
end

Finally, it is time to render errors inside our controller:
app/controllers/api/v1/patients_controller.rb

module Api
  module V1
    class PatientsController < V1::ApplicationController

      def calculate_something
        service_response = MyService.calculate_a_thing(my_strong_parameters)

        if service_response.valid?
          render json { ... }, status: :ok
        else
          render json: service_response.errors, status: 422
        end
      end
    end
end

There you go!, keep reading, coding and relax!

No Comments

Post A Comment