Class: ApiMaker::ValidationErrorsGeneratorService

Inherits:
ApplicationService
  • Object
show all
Defined in:
app/services/api_maker/validation_errors_generator_service.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationService

#api_maker_json

Constructor Details

#initialize(model:, params:) ⇒ ValidationErrorsGeneratorService

Returns a new instance of ValidationErrorsGeneratorService.



4
5
6
7
8
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 4

def initialize(model:, params:)
  @model = model
  @params = params
  @result = []
end

Instance Attribute Details

#modelObject (readonly)

Returns the value of attribute model.



2
3
4
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 2

def model
  @model
end

#paramsObject (readonly)

Returns the value of attribute params.



2
3
4
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 2

def params
  @params
end

#resultObject (readonly)

Returns the value of attribute result.



2
3
4
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 2

def result
  @result
end

Instance Method Details

#all_keys_numeric?(hash) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 98

def all_keys_numeric?(hash)
  hash.keys.all? { |key| key.to_s.match?(/\A\d+\Z/) }
end

#attribute_type(model, attribute_name) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 51

def attribute_type(model, attribute_name)
  if model.attribute_names.include?(attribute_name.to_s)
    :attribute
  elsif model.class.const_defined?(:ADDITIONAL_ATTRIBUTES_FOR_VALIDATION_ERRORS) &&
      model.class.const_get(:ADDITIONAL_ATTRIBUTES_FOR_VALIDATION_ERRORS).include?(attribute_name)
    :additional_attribute_for_validation
  elsif model._reflections.key?(attribute_name.to_s)
    :reflection
  elsif model.class.try(:monetized_attributes)&.include?(attribute_name.to_s)
    :monetized_attribute
  elsif attribute_name == :base
    :base
  end
end

#check_nested_many_models_for_validation_errors(models_up_next, attribute_value, path) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 102

def check_nested_many_models_for_validation_errors(models_up_next, attribute_value, path)
  if models_up_next.length != attribute_value.keys.length
    raise "Expected same length on targets and attribute values: #{models_up_next.length}, #{attribute_value.keys.length}"
  end

  count = 0
  attribute_value.each do |unique_key, model_attribute_values|
    model_up_next = models_up_next.fetch(count)
    count += 1

    path << unique_key
    inspect_model(model_up_next, path)
    inspect_params(model_up_next, model_attribute_values, path)
    path.pop
  end
end

#check_nested_many_models_for_validation_errors_on_array(models_up_next, attribute_value, path) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 119

def check_nested_many_models_for_validation_errors_on_array(models_up_next, attribute_value, path)
  if models_up_next.length != attribute_value.length
    raise "Expected same length on targets and attribute values: #{models_up_next.length}, #{attribute_value.length}"
  end

  count = 0
  attribute_value.each_with_index do |model_attribute_values, unique_key|
    model_up_next = models_up_next.fetch(count)
    count += 1

    path << unique_key
    inspect_model(model_up_next, path)
    inspect_params(model_up_next, model_attribute_values, path)
    path.pop
  end
end

#error_type(attribute_type, error) ⇒ Object



66
67
68
69
70
71
72
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 66

def error_type(attribute_type, error)
  if attribute_type == :base
    :base
  else
    error.fetch(:error)
  end
end

#inspect_model(model, path) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 18

def inspect_model(model, path)
  return if model.errors.empty?

  model.errors.details.each do |attribute_name, _errors|
    attribute_type = attribute_type(model, attribute_name)
    next unless attribute_type

    attribute_path = path + [attribute_name]
    input_name = path_to_attribute_name(attribute_path)

    error_data = {
      attribute_name: attribute_name,
      attribute_type: attribute_type,
      id: model.id,
      model_name: model.model_name.param_key,
      error_messages: model.errors.messages.fetch(attribute_name).to_a,
      error_types: model.errors.details.fetch(attribute_name).map do |error|
        error = error.fetch(:error)

        if error.is_a?(Symbol)
          error
        else
          :custom_error
        end
      end
    }

    error_data[:input_name] = input_name unless attribute_type == :base

    result << error_data
  end
end

#inspect_params(model, params, path) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 74

def inspect_params(model, params, path)
  params.each do |attribute_name, attribute_value|
    match = attribute_name.match(/\A(.+)_attributes\Z/)
    next unless match

    association_name = match[1].to_sym
    association = model.association(association_name)

    path << attribute_name

    if attribute_value.is_a?(Array)
      check_nested_many_models_for_validation_errors_on_array(association.target, attribute_value, path)
    elsif all_keys_numeric?(attribute_value)
      # This is a has-many relationship where keys are mapped to attributes
      check_nested_many_models_for_validation_errors(association.target, attribute_value, path)
    else
      inspect_model(association.target, path)
      inspect_params(association.target, attribute_value, path)
    end

    path.pop
  end
end

#path_to_attribute_name(original_attribute_path) ⇒ Object



136
137
138
139
140
141
142
143
144
145
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 136

def path_to_attribute_name(original_attribute_path)
  attribute_path = original_attribute_path.dup
  path_string = attribute_path.shift.dup

  attribute_path.each do |path_part|
    path_string << "[#{path_part}]"
  end

  path_string
end

#performObject



10
11
12
13
14
15
16
# File 'app/services/api_maker/validation_errors_generator_service.rb', line 10

def perform
  path = [model.model_name.singular]

  inspect_model(model, path)
  inspect_params(model, params, path)
  ServicePattern::Response.new(result: result)
end