Class: SimpleRubyService::Errors

Inherits:
Object
  • Object
show all
Defined in:
lib/simple_ruby_service/errors.rb

Overview

Extnding ActiveModel::Errors with additional features:

  1. Adds ability to return array of errors

  2. Adds ability to decorate errors

  3. Adds ability to internationalize errors

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base) ⇒ Errors

Returns a new instance of Errors.



14
15
16
17
18
# File 'lib/simple_ruby_service/errors.rb', line 14

def initialize(base)
  @base = base
  @original_errors = []
  @active_model_errors = ActiveModel::Errors.new(base)
end

Instance Attribute Details

#active_model_errorsObject (readonly)

Returns the value of attribute active_model_errors.



12
13
14
# File 'lib/simple_ruby_service/errors.rb', line 12

def active_model_errors
  @active_model_errors
end

#original_errorsObject (readonly)

Returns the value of attribute original_errors.



11
12
13
# File 'lib/simple_ruby_service/errors.rb', line 11

def original_errors
  @original_errors
end

Instance Method Details

#add(attribute, message = :invalid, options = {}) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/simple_ruby_service/errors.rb', line 20

def add(attribute, message = :invalid, options = {})
  # store original arguments, since Rails 5 errors don't store `message`, only it's translation.
  # can be avoided with Rails 6.
  original_errors << OpenStruct.new(
    attribute: attribute,
    message: message,
    options: options
  )
  active_model_errors.add(attribute, message, options)
end

#api_errors(&decorate_error) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/simple_ruby_service/errors.rb', line 31

def api_errors(&decorate_error)
  original_errors.map do |e|
    type = e.message.is_a?(Symbol) ? e.message : nil
    message = type ? active_model_errors.generate_message(e.attribute, e.message, e.options) : e.message
    full_message = full_message(e.attribute, message)

    error = {
      full_message: full_message,
      message: message,
      type: type,
      attribute: e.attribute,
      options: e.options
    }

    error = decorate_error.call(error) if decorate_error
    error
  end
end

#clearObject



78
79
80
81
# File 'lib/simple_ruby_service/errors.rb', line 78

def clear
  original_errors.clear
  active_model_errors.clear
end

#full_message(attribute, message) ⇒ Object

Support ovveriding format for each error (not avaliable in rails 5)



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/simple_ruby_service/errors.rb', line 51

def full_message(attribute, message)
  return message if attribute == :base

  attr_name = attribute.to_s.tr('.', '_').humanize
  attr_name = @base.class.human_attribute_name(attribute, default: attr_name)

  defaults = i18n_keys(attribute, '_format')
  defaults << :"errors.format"
  defaults << '%{attribute} %{message}'

  I18n.t(defaults.shift,
         default: defaults,
         attribute: attr_name,
         message: message)
end

#i18n_keys(attribute, key) ⇒ Object



67
68
69
70
71
72
73
74
75
76
# File 'lib/simple_ruby_service/errors.rb', line 67

def i18n_keys(attribute, key)
  if @base.class.respond_to?(:i18n_scope)
    i18n_scope = @base.class.i18n_scope.to_s
    @base.class.lookup_ancestors.flat_map do |klass|
      [:"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{key}"]
    end
  else
    []
  end
end