Skip to content

Instantly share code, notes, and snippets.

@IlyaDonskikh
Last active December 3, 2019 13:42
Show Gist options
  • Save IlyaDonskikh/3e20a5f43d932d5c7bb66e2af8f51764 to your computer and use it in GitHub Desktop.
Save IlyaDonskikh/3e20a5f43d932d5c7bb66e2af8f51764 to your computer and use it in GitHub Desktop.
Services Concept
# frozen_string_literal: true
class ApplicationService
attr_reader :errors
## Etc.
def self.call(params)
new(params).process
end
def initialize(params = {}) # partent service method
params.each do |attr, value|
self.public_send("#{attr}=", value)
end
@errors = ErrorService.new(self)
end
def process
self
end
def success?
errors.blank?
end
def failed?
!success
end
private
def valid?
validate!
success?
end
end
class ErrorService
attr_reader :caller_instance
def initialize(caller_instance)
@caller_instance = caller_instance
end
def errors
@errors ||= {}
end
def messages(flat: false)
messages = {}
errors.each do |key, value|
key_localized = localize(".keys.#{key}")
messages[key] =
value.map do |message|
message_localized = localize(".values.#{key}.#{message}")
"#{key_localized} #{message_localized}"
end
end
flat ? flatten_messages(messages) : messages
end
def blank?
errors.empty?
end
def add(key, value)
# ToDo: Add only uniq
list = errors[key]
return errors[key] = [value] unless list
errors[key] = list.push(value)
end
private
def localize(name, attrs = {})
hierarchy_path = caller_instance.class.to_s.underscore.gsub('/', '.')
I18n.t("services.#{hierarchy_path}.errors.#{name}", attrs)
end
def flatten_messages(messages)
messages.map { |_, value| value }.flatten
end
end
# frozen_string_literal: true
class MakeItSimple < ApplicationService
attr_accessor :company_id, :chain_id, :group_id, :step
## Consts
VALID_CHAIN_WORKFLOW_STATES = %w(initialized rejected)
## Etc.
def process
assing_items! if valid?
super
end
private
def assing_items!
emails = group.users_of_self_and_descendants.pluck(:email)
emails.each { |e| chain.approval_results.create(step: step, email: e) }
end
def group
@group ||= Group.of_company(company_id).find_by(id: group_id)
end
def chain
# Have to add company id to the chain table for security reasons
@chain ||= ApprovalResultChain.find_by(id: chain_id)
end
def validate!
errors.add(:company_id, :blank) unless company_id
errors.add(:group_id, :present) unless group
errors.add(:chain_id, :present) unless chain
errors.add(:chain_id, :invalid_state) unless chain_state_is_valid?
errors.add(:step, :invalid) unless step_valid?
end
def step_valid?
return true unless chain
chain.available_steps.include?(step.to_i)
end
def chain_state_is_valid?
return true unless chain
state = chain.find_state_machine(Workflow::APPROVAL_RESULT_WORKFLOW).state_id
VALID_CHAIN_WORKFLOW_STATES.include? state
end
end
service = MakeItSimple.call(company_id: compnay.id)
service.success? => # false
service.errors.messages => { chain_id: [Цепочка согласований не указана, ..], .. }
service.errors.messages(flat: true) => [Цепочка согласований не указана, .., ..]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment