ActionService v2.x

Welcome to Action Service gem, is a ruby gem to create and interact easily with services.

Why services

This is where you can add your code to perform a simple function instead of making complex controllers or models.

Installation

Add this line to your application's Gemfile:

gem 'action_service'

And then execute:

$ bundle

Or install it yourself as:

$ gem install action_service

Setting up

To start to use the gem execute:

$ rails g service:application_service

This command will generate application service (is the parent class for all your services), application service is inheriting from the action service base class, and you can overwrite all methods.

Usage

You can start to use action service by generating service to execute a specific logic, Example: Run next command to generate service for authenticating an admin

$ rails g service Admin::Authenticate

this will add a new directory for admin inside app/services if not exist, and generate authenticate_service.rb

Running via Spring preloader in process 30051
      create  app/services/admin/authenticate_service.rb

And when you open authenticate_service.rb will be like this

class Admin::AuthenticateService < ApplicationService
  def initialize()
    super()
  end

  def call
    self
  end
end

ApplicationService class

All generated services are inheriting from ApplcaitonService, ApplicationService is inherited from `ActoinService::Base, So all service will contain:

Three instance variables

  1. @success is a boolean with true as the default value, and if you add any error this flag will be changed to false.
  2. @errors is an array containing a list of errors.
  3. @response is a hash to add service response (values, objects, etc.). #### Six instance methods
  4. success? to get boolean if service is executed successfully or not (based on adding errors).
  5. errors to get a list of errors.
  6. response to get the response hash.
  7. add_error(error_message) to add error (will change @success to false), Example add_error("wrong admin id").
  8. add_errors(*error_messages) to add errors as parameters or array (will change @success to false), Example add_errors("email is required","phone number is aready exist") OR add_errors(["email is required","phone number is aready exist"]).

Now, let's implement Admin::AuthenticateService

class Admin::AuthenticateService < ApplicationService
  def initialize(email, password)
    super()
    @admin = Admin.find_by(email: email)
    @password = password
  end

  def call
    add_error "wrong admin email" and return self if not @admin
    add_error "wrong password" and return self if not @admin.authenticate(@password)
    @response[:admin] = @admin
    self
  end
end

This service is now ready to be used, For example, we will call the service inside a controller

result =  Admin::AuthenticateService.new(params[:email], params[:password]).call
if result.success?
  # {success: true, response: {admin object}, errors: []}
  render json: { success: result.success?, response: result.response, errors: result.errors }
else
  # {success: false, response: {}, errors: ["wrong email" OR "wrong password"]}
  render json: { success: result.success?, response: result.response, errors: result.errors }, status: :unauthorized
end

Services layer will help you to write clean code, by small models, controller and DRY code (don't repeat yourself), you can use service inside another service and stop executing the first service if the second one fails, Example:

class Cache::List::AddHashService < ApplicationService
  def initialize(list_key, hash_key, hash_data, expiry_datetime=nil)
    super()
    @list_key = list_key
    @hash_key = hash_key
    @hash = hash_data
    @expiry_datetime = expiry_datetime
  end

  def call
    result = Cache::Hash::SetService.new(hash_key, hash_data, @expiry_datetime).call
    # if Cache::Hash::SetService fails will stop excuting and return the errors
    add_errors result.errors and return self if not result.success? 
    result = Cache::List::AddService.new(list_key, hash_key, @expiry_datetime).call
    # if Cache::List::AddService fails will stop excuting and return the errors
    add_errors result.errors and return self if not result.success?
    self
  end
end

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/abdofawzi5/action_service. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open-source under the terms of the MIT License.