action_processor 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/action_processor/base.rb +130 -0
- data/lib/action_processor/errors.rb +46 -0
- data/lib/action_processor.rb +2 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4771896f3d4045a45c5b2913c6eecb27f17d9814f027ac6faa343fba0fb3cc04
|
4
|
+
data.tar.gz: 3212b5d960508dc66eb1ddfeb7b1f1bec9617d3bedfffda59e8332454af002e8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b277de0643b7abff6121730e1e44fe5a556bc5e0d303c3408c0b39fcffaa5365ff9505632a67a37495662acc386484b8d96f6bdaa50d721d7076bd53ad89bd41
|
7
|
+
data.tar.gz: c3ed077263b9ab97812052e99d4288de3236b02182f19b98a396375b6eb35760f38c75fe64bea59ba99a57673c92ab4287f7cf9add4c25b54c23e449f69615d4
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
4
|
+
require "active_record"
|
5
|
+
|
6
|
+
module ActionProcessor
|
7
|
+
class Base
|
8
|
+
attr_reader :params, :errors
|
9
|
+
|
10
|
+
def self.run(params = {})
|
11
|
+
inst = new(params)
|
12
|
+
inst.run
|
13
|
+
inst
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(params = {})
|
17
|
+
@params = if params.class.name == 'Hash'
|
18
|
+
params.with_indifferent_access
|
19
|
+
else
|
20
|
+
params
|
21
|
+
end
|
22
|
+
@errors = ActionProcessor::Errors.new
|
23
|
+
@steps_stack = []
|
24
|
+
@transaction_level = ActiveRecord::Base.connection.open_transactions
|
25
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
26
|
+
@transaction_level = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
raise 'Error: method "run" should be overridden to implement business logic!'
|
31
|
+
end
|
32
|
+
|
33
|
+
def errors?
|
34
|
+
@errors.all.any?
|
35
|
+
end
|
36
|
+
|
37
|
+
def success?
|
38
|
+
@errors.all.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def json_outcome
|
42
|
+
errors? ? failed_json : successful_json
|
43
|
+
end
|
44
|
+
|
45
|
+
# in most cases should be overriden to provide relevant data
|
46
|
+
def successful_json
|
47
|
+
{ success: true }
|
48
|
+
end
|
49
|
+
|
50
|
+
# could be overriden to provide some specifics/advices/etc.
|
51
|
+
def failed_json
|
52
|
+
{ success: false, errors: errors.grouped_by_attribute }
|
53
|
+
end
|
54
|
+
|
55
|
+
def step(step_method, **options)
|
56
|
+
return if errors? # skip it if there are errors
|
57
|
+
|
58
|
+
step_always(step_method, **options)
|
59
|
+
end
|
60
|
+
|
61
|
+
def step_always(step_method, **options)
|
62
|
+
@steps_stack << (@current_step || :not_specified)
|
63
|
+
@current_step = step_method
|
64
|
+
# performs even if there are errors
|
65
|
+
# useful for:
|
66
|
+
# - validation steps to return list of all errors
|
67
|
+
# - errors reporting and making decisions at the end of processing
|
68
|
+
send step_method, **options
|
69
|
+
@current_step = @steps_stack.pop
|
70
|
+
end
|
71
|
+
|
72
|
+
# As an "errs" params we could pass several types:
|
73
|
+
# - String with error description
|
74
|
+
# - array of Strings (error messages)
|
75
|
+
# - ActiveRecord model (invalid) - its errors will be copied
|
76
|
+
def fail!(errs, attr = :not_specified)
|
77
|
+
if errs.class.ancestors.map(&:to_s).include?("ActiveRecord::Base")
|
78
|
+
fail_active_record!(errs)
|
79
|
+
else
|
80
|
+
@errors.add(errs, @current_step, attr)
|
81
|
+
end
|
82
|
+
|
83
|
+
raise ActiveRecord::Rollback if in_transaction?
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# simple params presence validation
|
89
|
+
# will initiate errors for each absent params
|
90
|
+
def required_params(*list)
|
91
|
+
list.flatten!
|
92
|
+
@list_of_allowed_params ||= []
|
93
|
+
@list_of_allowed_params += list.map(&:to_s)
|
94
|
+
list.map(&:to_s).each do |param|
|
95
|
+
next if params[param].present?
|
96
|
+
|
97
|
+
fail! "Parameter :#{param} should be present", param
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# allowed params (in addition to required_params)
|
102
|
+
# if allowed_params present method called, all params
|
103
|
+
# provided to Processor which are not included in
|
104
|
+
# lists specified for required_params and allowed_params
|
105
|
+
# will cause validation error
|
106
|
+
def allowed_params(*list)
|
107
|
+
list.flatten!
|
108
|
+
@list_of_allowed_params ||= []
|
109
|
+
@list_of_allowed_params += list.map(&:to_s)
|
110
|
+
|
111
|
+
params.each do |key, value|
|
112
|
+
next if @list_of_allowed_params.index(key.to_s).present?
|
113
|
+
|
114
|
+
fail! "Parameter :#{key} is not allowed", key.to_sym
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def fail_active_record!(record)
|
119
|
+
record.errors.each do |err|
|
120
|
+
fail! "#{err.attribute.to_s.humanize} #{err.message}", err.attribute
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def in_transaction?
|
125
|
+
return false if @transaction_level.nil?
|
126
|
+
|
127
|
+
ActiveRecord::Base.connection.open_transactions > @transaction_level
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
4
|
+
|
5
|
+
module ActionProcessor
|
6
|
+
class Errors
|
7
|
+
attr_reader :all
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@all = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(messages, step = :not_specified, attribute = :not_specified)
|
14
|
+
step ||= :not_specified # in case we will receive explicit nil as step parameter
|
15
|
+
@all << { messages: [messages].flatten, step: step.to_sym, attribute: attribute.to_sym }
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns array of strings with user friendly error messages
|
19
|
+
def messages
|
20
|
+
all_messages = []
|
21
|
+
@all.each do |e|
|
22
|
+
all_messages += e[:messages]
|
23
|
+
end
|
24
|
+
all_messages
|
25
|
+
end
|
26
|
+
|
27
|
+
alias full_messages messages # for compatibility with ActiveRecord::Errors
|
28
|
+
|
29
|
+
def for_attribute(attr)
|
30
|
+
@grouped_by_attribute[attr]
|
31
|
+
end
|
32
|
+
|
33
|
+
def grouped_by_attribute
|
34
|
+
return @grouped_by_attribute if @grouped_by_attribute.present?
|
35
|
+
|
36
|
+
# we assume that all errors will be present
|
37
|
+
# at the time when this method called first time
|
38
|
+
@grouped_by_attribute = {}.with_indifferent_access
|
39
|
+
@all.each do |err|
|
40
|
+
@grouped_by_attribute[err.attribute] ||= []
|
41
|
+
@grouped_by_attribute[err.attribute] += err[:messages]
|
42
|
+
end
|
43
|
+
@grouped_by_attribute
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: action_processor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ghennadii Mirosnicenco
|
8
|
+
- Pavel Mirosnicenco
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2023-02-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 7.0.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 7.0.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activerecord
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 7.0.0
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 7.0.0
|
42
|
+
description: action_processor
|
43
|
+
email: linkator7@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/action_processor.rb
|
49
|
+
- lib/action_processor/base.rb
|
50
|
+
- lib/action_processor/errors.rb
|
51
|
+
homepage: https://github.com/GhennadiiMir/action_processor
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '3'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubygems_version: 3.3.7
|
71
|
+
signing_key:
|
72
|
+
specification_version: 4
|
73
|
+
summary: Group each of your complex multy-model manipulations in dedicated ActionProcessor
|
74
|
+
test_files: []
|