auxiliary_rails 0.2.0 → 0.4.0

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +26 -0
  3. data/.rubocop.yml +31 -3
  4. data/.rubocop_todo.yml +3 -19
  5. data/.ruby-version +1 -1
  6. data/.yardopts +5 -0
  7. data/CHANGELOG.md +39 -2
  8. data/CODE_OF_CONDUCT.md +128 -0
  9. data/CONTRIBUTING.md +0 -6
  10. data/Gemfile.lock +164 -132
  11. data/README.md +267 -5
  12. data/auxiliary_rails.gemspec +18 -13
  13. data/bin/rspec +29 -0
  14. data/bin/rubocop +29 -0
  15. data/bitbucket-pipelines.yml +35 -0
  16. data/lib/auxiliary_rails/application/command.rb +53 -0
  17. data/lib/auxiliary_rails/application/error.rb +50 -0
  18. data/lib/auxiliary_rails/application/form.rb +31 -0
  19. data/lib/auxiliary_rails/application/query.rb +75 -0
  20. data/lib/auxiliary_rails/application/service.rb +42 -0
  21. data/lib/auxiliary_rails/cli.rb +18 -5
  22. data/lib/auxiliary_rails/concerns/callable.rb +23 -0
  23. data/lib/auxiliary_rails/concerns/errorable.rb +22 -0
  24. data/lib/auxiliary_rails/concerns/performable.rb +120 -0
  25. data/lib/auxiliary_rails/railtie.rb +2 -1
  26. data/lib/auxiliary_rails/version.rb +1 -1
  27. data/lib/auxiliary_rails/view_helpers/display_helper.rb +30 -0
  28. data/lib/auxiliary_rails/view_helpers.rb +4 -0
  29. data/lib/auxiliary_rails.rb +7 -3
  30. data/lib/generators/auxiliary_rails/command_generator.rb +1 -1
  31. data/lib/generators/auxiliary_rails/install_commands_generator.rb +5 -0
  32. data/lib/generators/auxiliary_rails/install_errors_controller_generator.rb +31 -0
  33. data/lib/generators/auxiliary_rails/install_generator.rb +1 -1
  34. data/lib/generators/auxiliary_rails/service_generator.rb +48 -0
  35. data/lib/generators/auxiliary_rails/templates/application_error_template.rb +1 -1
  36. data/lib/generators/auxiliary_rails/templates/commands/application_command_template.rb +1 -1
  37. data/lib/generators/auxiliary_rails/templates/commands/command_spec_template.rb +1 -1
  38. data/lib/generators/auxiliary_rails/templates/commands/command_template.rb +2 -2
  39. data/lib/generators/auxiliary_rails/templates/commands/commands.en_template.yml +5 -0
  40. data/lib/generators/auxiliary_rails/templates/errors_controller/errors_controller_template.rb +15 -0
  41. data/lib/generators/auxiliary_rails/templates/errors_controller/not_found_template.html.erb +2 -0
  42. data/lib/generators/auxiliary_rails/templates/errors_controller/show_template.html.erb +1 -0
  43. data/lib/generators/auxiliary_rails/templates/errors_controller/unacceptable_template.html.erb +2 -0
  44. data/lib/generators/auxiliary_rails/templates/services/service_spec_template.rb +5 -0
  45. data/lib/generators/auxiliary_rails/templates/services/service_template.rb +10 -0
  46. data/templates/rails/elementary.rb +39 -10
  47. metadata +87 -32
  48. data/lib/auxiliary_rails/abstract_command.rb +0 -95
  49. data/lib/auxiliary_rails/abstract_error.rb +0 -7
  50. data/lib/generators/auxiliary_rails/install_rubocop_generator.rb +0 -29
  51. data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_auxiliary_rails_template.yml +0 -65
  52. data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_template.yml +0 -11
data/Gemfile.lock CHANGED
@@ -1,177 +1,209 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- auxiliary_rails (0.2.0)
4
+ auxiliary_rails (0.4.0)
5
+ dry-core
6
+ dry-initializer
5
7
  dry-initializer-rails
8
+ rails (>= 5.2)
6
9
  thor
7
10
 
8
11
  GEM
9
12
  remote: https://rubygems.org/
10
13
  specs:
11
- actioncable (6.0.2.1)
12
- actionpack (= 6.0.2.1)
14
+ actioncable (7.0.3.1)
15
+ actionpack (= 7.0.3.1)
16
+ activesupport (= 7.0.3.1)
13
17
  nio4r (~> 2.0)
14
18
  websocket-driver (>= 0.6.1)
15
- actionmailbox (6.0.2.1)
16
- actionpack (= 6.0.2.1)
17
- activejob (= 6.0.2.1)
18
- activerecord (= 6.0.2.1)
19
- activestorage (= 6.0.2.1)
20
- activesupport (= 6.0.2.1)
19
+ actionmailbox (7.0.3.1)
20
+ actionpack (= 7.0.3.1)
21
+ activejob (= 7.0.3.1)
22
+ activerecord (= 7.0.3.1)
23
+ activestorage (= 7.0.3.1)
24
+ activesupport (= 7.0.3.1)
21
25
  mail (>= 2.7.1)
22
- actionmailer (6.0.2.1)
23
- actionpack (= 6.0.2.1)
24
- actionview (= 6.0.2.1)
25
- activejob (= 6.0.2.1)
26
+ net-imap
27
+ net-pop
28
+ net-smtp
29
+ actionmailer (7.0.3.1)
30
+ actionpack (= 7.0.3.1)
31
+ actionview (= 7.0.3.1)
32
+ activejob (= 7.0.3.1)
33
+ activesupport (= 7.0.3.1)
26
34
  mail (~> 2.5, >= 2.5.4)
35
+ net-imap
36
+ net-pop
37
+ net-smtp
27
38
  rails-dom-testing (~> 2.0)
28
- actionpack (6.0.2.1)
29
- actionview (= 6.0.2.1)
30
- activesupport (= 6.0.2.1)
31
- rack (~> 2.0, >= 2.0.8)
39
+ actionpack (7.0.3.1)
40
+ actionview (= 7.0.3.1)
41
+ activesupport (= 7.0.3.1)
42
+ rack (~> 2.0, >= 2.2.0)
32
43
  rack-test (>= 0.6.3)
33
44
  rails-dom-testing (~> 2.0)
34
45
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
35
- actiontext (6.0.2.1)
36
- actionpack (= 6.0.2.1)
37
- activerecord (= 6.0.2.1)
38
- activestorage (= 6.0.2.1)
39
- activesupport (= 6.0.2.1)
46
+ actiontext (7.0.3.1)
47
+ actionpack (= 7.0.3.1)
48
+ activerecord (= 7.0.3.1)
49
+ activestorage (= 7.0.3.1)
50
+ activesupport (= 7.0.3.1)
51
+ globalid (>= 0.6.0)
40
52
  nokogiri (>= 1.8.5)
41
- actionview (6.0.2.1)
42
- activesupport (= 6.0.2.1)
53
+ actionview (7.0.3.1)
54
+ activesupport (= 7.0.3.1)
43
55
  builder (~> 3.1)
44
56
  erubi (~> 1.4)
45
57
  rails-dom-testing (~> 2.0)
46
58
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
47
- activejob (6.0.2.1)
48
- activesupport (= 6.0.2.1)
59
+ activejob (7.0.3.1)
60
+ activesupport (= 7.0.3.1)
49
61
  globalid (>= 0.3.6)
50
- activemodel (6.0.2.1)
51
- activesupport (= 6.0.2.1)
52
- activerecord (6.0.2.1)
53
- activemodel (= 6.0.2.1)
54
- activesupport (= 6.0.2.1)
55
- activestorage (6.0.2.1)
56
- actionpack (= 6.0.2.1)
57
- activejob (= 6.0.2.1)
58
- activerecord (= 6.0.2.1)
59
- marcel (~> 0.3.1)
60
- activesupport (6.0.2.1)
62
+ activemodel (7.0.3.1)
63
+ activesupport (= 7.0.3.1)
64
+ activerecord (7.0.3.1)
65
+ activemodel (= 7.0.3.1)
66
+ activesupport (= 7.0.3.1)
67
+ activestorage (7.0.3.1)
68
+ actionpack (= 7.0.3.1)
69
+ activejob (= 7.0.3.1)
70
+ activerecord (= 7.0.3.1)
71
+ activesupport (= 7.0.3.1)
72
+ marcel (~> 1.0)
73
+ mini_mime (>= 1.1.0)
74
+ activesupport (7.0.3.1)
61
75
  concurrent-ruby (~> 1.0, >= 1.0.2)
62
- i18n (>= 0.7, < 2)
63
- minitest (~> 5.1)
64
- tzinfo (~> 1.1)
65
- zeitwerk (~> 2.2)
66
- ast (2.4.0)
76
+ i18n (>= 1.6, < 2)
77
+ minitest (>= 5.1)
78
+ tzinfo (~> 2.0)
79
+ ast (2.4.2)
67
80
  builder (3.2.4)
68
- coderay (1.1.2)
69
- concurrent-ruby (1.1.5)
70
- crass (1.0.5)
71
- diff-lcs (1.3)
72
- dry-initializer (3.0.2)
81
+ coderay (1.1.3)
82
+ concurrent-ruby (1.1.10)
83
+ crass (1.0.6)
84
+ diff-lcs (1.5.0)
85
+ digest (3.1.0)
86
+ dry-core (0.8.1)
87
+ concurrent-ruby (~> 1.0)
88
+ dry-initializer (3.1.1)
73
89
  dry-initializer-rails (3.1.1)
74
90
  dry-initializer (>= 2.4, < 4)
75
91
  rails (> 3.0)
76
- erubi (1.9.0)
77
- globalid (0.4.2)
78
- activesupport (>= 4.2.0)
79
- i18n (1.7.0)
92
+ erubi (1.11.0)
93
+ globalid (1.0.0)
94
+ activesupport (>= 5.0)
95
+ i18n (1.12.0)
80
96
  concurrent-ruby (~> 1.0)
81
- jaro_winkler (1.5.4)
82
- loofah (2.4.0)
97
+ loofah (2.18.0)
83
98
  crass (~> 1.0.2)
84
99
  nokogiri (>= 1.5.9)
85
100
  mail (2.7.1)
86
101
  mini_mime (>= 0.1.1)
87
- marcel (0.3.3)
88
- mimemagic (~> 0.3.2)
89
- method_source (0.9.2)
90
- mimemagic (0.3.3)
91
- mini_mime (1.0.2)
92
- mini_portile2 (2.4.0)
93
- minitest (5.13.0)
94
- nio4r (2.5.2)
95
- nokogiri (1.10.7)
96
- mini_portile2 (~> 2.4.0)
97
- parallel (1.19.1)
98
- parser (2.7.0.1)
99
- ast (~> 2.4.0)
100
- pry (0.12.2)
101
- coderay (~> 1.1.0)
102
- method_source (~> 0.9.0)
103
- rack (2.0.8)
104
- rack-test (1.1.0)
105
- rack (>= 1.0, < 3)
106
- rails (6.0.2.1)
107
- actioncable (= 6.0.2.1)
108
- actionmailbox (= 6.0.2.1)
109
- actionmailer (= 6.0.2.1)
110
- actionpack (= 6.0.2.1)
111
- actiontext (= 6.0.2.1)
112
- actionview (= 6.0.2.1)
113
- activejob (= 6.0.2.1)
114
- activemodel (= 6.0.2.1)
115
- activerecord (= 6.0.2.1)
116
- activestorage (= 6.0.2.1)
117
- activesupport (= 6.0.2.1)
118
- bundler (>= 1.3.0)
119
- railties (= 6.0.2.1)
120
- sprockets-rails (>= 2.0.0)
102
+ marcel (1.0.2)
103
+ method_source (1.0.0)
104
+ mini_mime (1.1.2)
105
+ mini_portile2 (2.8.0)
106
+ minitest (5.16.3)
107
+ net-imap (0.2.3)
108
+ digest
109
+ net-protocol
110
+ strscan
111
+ net-pop (0.1.1)
112
+ digest
113
+ net-protocol
114
+ timeout
115
+ net-protocol (0.1.3)
116
+ timeout
117
+ net-smtp (0.3.1)
118
+ digest
119
+ net-protocol
120
+ timeout
121
+ nio4r (2.5.8)
122
+ nokogiri (1.13.8)
123
+ mini_portile2 (~> 2.8.0)
124
+ racc (~> 1.4)
125
+ parallel (1.22.1)
126
+ parser (3.1.2.1)
127
+ ast (~> 2.4.1)
128
+ pry (0.14.1)
129
+ coderay (~> 1.1)
130
+ method_source (~> 1.0)
131
+ racc (1.6.0)
132
+ rack (2.2.4)
133
+ rack-test (2.0.2)
134
+ rack (>= 1.3)
135
+ rails (7.0.3.1)
136
+ actioncable (= 7.0.3.1)
137
+ actionmailbox (= 7.0.3.1)
138
+ actionmailer (= 7.0.3.1)
139
+ actionpack (= 7.0.3.1)
140
+ actiontext (= 7.0.3.1)
141
+ actionview (= 7.0.3.1)
142
+ activejob (= 7.0.3.1)
143
+ activemodel (= 7.0.3.1)
144
+ activerecord (= 7.0.3.1)
145
+ activestorage (= 7.0.3.1)
146
+ activesupport (= 7.0.3.1)
147
+ bundler (>= 1.15.0)
148
+ railties (= 7.0.3.1)
121
149
  rails-dom-testing (2.0.3)
122
150
  activesupport (>= 4.2.0)
123
151
  nokogiri (>= 1.6)
124
- rails-html-sanitizer (1.3.0)
152
+ rails-html-sanitizer (1.4.3)
125
153
  loofah (~> 2.3)
126
- railties (6.0.2.1)
127
- actionpack (= 6.0.2.1)
128
- activesupport (= 6.0.2.1)
154
+ railties (7.0.3.1)
155
+ actionpack (= 7.0.3.1)
156
+ activesupport (= 7.0.3.1)
129
157
  method_source
130
- rake (>= 0.8.7)
131
- thor (>= 0.20.3, < 2.0)
132
- rainbow (3.0.0)
133
- rake (13.0.1)
134
- rspec (3.9.0)
135
- rspec-core (~> 3.9.0)
136
- rspec-expectations (~> 3.9.0)
137
- rspec-mocks (~> 3.9.0)
138
- rspec-core (3.9.1)
139
- rspec-support (~> 3.9.1)
140
- rspec-expectations (3.9.0)
158
+ rake (>= 12.2)
159
+ thor (~> 1.0)
160
+ zeitwerk (~> 2.5)
161
+ rainbow (3.1.1)
162
+ rake (13.0.6)
163
+ regexp_parser (2.5.0)
164
+ rexml (3.2.5)
165
+ rspec (3.11.0)
166
+ rspec-core (~> 3.11.0)
167
+ rspec-expectations (~> 3.11.0)
168
+ rspec-mocks (~> 3.11.0)
169
+ rspec-core (3.11.0)
170
+ rspec-support (~> 3.11.0)
171
+ rspec-expectations (3.11.0)
141
172
  diff-lcs (>= 1.2.0, < 2.0)
142
- rspec-support (~> 3.9.0)
143
- rspec-mocks (3.9.1)
173
+ rspec-support (~> 3.11.0)
174
+ rspec-mocks (3.11.1)
144
175
  diff-lcs (>= 1.2.0, < 2.0)
145
- rspec-support (~> 3.9.0)
146
- rspec-support (3.9.2)
147
- rubocop (0.78.0)
148
- jaro_winkler (~> 1.5.1)
176
+ rspec-support (~> 3.11.0)
177
+ rspec-support (3.11.0)
178
+ rubocop (1.20.0)
149
179
  parallel (~> 1.10)
150
- parser (>= 2.6)
180
+ parser (>= 3.0.0.0)
151
181
  rainbow (>= 2.2.2, < 4.0)
182
+ regexp_parser (>= 1.8, < 3.0)
183
+ rexml
184
+ rubocop-ast (>= 1.9.1, < 2.0)
152
185
  ruby-progressbar (~> 1.7)
153
- unicode-display_width (>= 1.4.0, < 1.7)
154
- rubocop-performance (1.5.2)
155
- rubocop (>= 0.71.0)
156
- rubocop-rspec (1.37.1)
157
- rubocop (>= 0.68.1)
158
- ruby-progressbar (1.10.1)
159
- sprockets (4.0.0)
186
+ unicode-display_width (>= 1.4.0, < 3.0)
187
+ rubocop-ast (1.21.0)
188
+ parser (>= 3.1.1.0)
189
+ rubocop-performance (1.14.3)
190
+ rubocop (>= 1.7.0, < 2.0)
191
+ rubocop-ast (>= 0.4.0)
192
+ rubocop-rake (0.6.0)
193
+ rubocop (~> 1.0)
194
+ rubocop-rspec (2.11.1)
195
+ rubocop (~> 1.19)
196
+ ruby-progressbar (1.11.0)
197
+ strscan (3.0.4)
198
+ thor (1.2.1)
199
+ timeout (0.3.0)
200
+ tzinfo (2.0.5)
160
201
  concurrent-ruby (~> 1.0)
161
- rack (> 1, < 3)
162
- sprockets-rails (3.2.1)
163
- actionpack (>= 4.0)
164
- activesupport (>= 4.0)
165
- sprockets (>= 3.0.0)
166
- thor (1.0.1)
167
- thread_safe (0.3.6)
168
- tzinfo (1.2.6)
169
- thread_safe (~> 0.1)
170
- unicode-display_width (1.6.0)
171
- websocket-driver (0.7.1)
202
+ unicode-display_width (2.2.0)
203
+ websocket-driver (0.7.5)
172
204
  websocket-extensions (>= 0.1.0)
173
- websocket-extensions (0.1.4)
174
- zeitwerk (2.2.2)
205
+ websocket-extensions (0.1.5)
206
+ zeitwerk (2.6.0)
175
207
 
176
208
  PLATFORMS
177
209
  ruby
@@ -180,12 +212,12 @@ DEPENDENCIES
180
212
  auxiliary_rails!
181
213
  bundler (~> 2.0)
182
214
  pry
183
- rails (>= 5.2, < 7)
184
215
  rake
185
216
  rspec (~> 3.8)
186
- rubocop
217
+ rubocop (= 1.20.0)
187
218
  rubocop-performance
219
+ rubocop-rake
188
220
  rubocop-rspec
189
221
 
190
222
  BUNDLED WITH
191
- 2.0.2
223
+ 2.1.4
data/README.md CHANGED
@@ -11,12 +11,15 @@ Collection of classes, configs, scripts, generators for Ruby on Rails helping yo
11
11
  Add one of these lines to your application's `Gemfile`:
12
12
 
13
13
  ```ruby
14
- # version released to RubyGems
14
+ # version released to RubyGems (recommended)
15
15
  gem 'auxiliary_rails'
16
+
16
17
  # or latest version from the repository
17
18
  gem 'auxiliary_rails', git: 'https://github.com/ergoserv/auxiliary_rails'
18
- # or from a specific branch of the repository
19
+ # or from a specific branch of the GitHub repository
19
20
  gem 'auxiliary_rails', github: 'ergoserv/auxiliary_rails', branch: 'develop'
21
+ # or from a local path (for development and testing purposes)
22
+ gem 'auxiliary_rails', path: '../auxiliary_rails'
20
23
  ```
21
24
 
22
25
  And then execute:
@@ -29,18 +32,22 @@ Or install it yourself as:
29
32
 
30
33
  ## Usage
31
34
 
35
+ - [API documentation](https://www.rubydoc.info/gems/auxiliary_rails)
36
+
32
37
  ### Rails Application Templates
33
38
 
34
39
  Install gem into the system (e.g. using `gem install auxiliary_rails`) then:
35
40
 
36
41
  ```sh
37
42
  auxiliary_rails new APP_PATH
43
+ # or add `--develop` option to pull the most recent template from repository
44
+ auxiliary_rails new APP_PATH --develop
38
45
  ```
39
46
 
40
47
  Or use `rails new` command specifying `--template` argument:
41
48
 
42
49
  ```sh
43
- rails new APP_PATH --skip-action-cable --skip-coffee --skip-test --database=postgresql --template=https://raw.githubusercontent.com/ergoserv/auxiliary_rails/develop/templates/rails/elementary.rb
50
+ rails new APP_PATH --database=postgresql --template=https://raw.githubusercontent.com/ergoserv/auxiliary_rails/develop/templates/rails/elementary.rb --skip-action-cable --skip-coffee --skip-test
44
51
  ```
45
52
 
46
53
  ### Generators
@@ -52,14 +59,268 @@ rails generate auxiliary_rails:install
52
59
  # Install one by one
53
60
  rails generate auxiliary_rails:install_commands
54
61
  rails generate auxiliary_rails:install_errors
55
- rails generate auxiliary_rails:install_rubocop
56
- rails generate auxiliary_rails:install_rubocop --no-specify-gems
62
+ rails generate auxiliary_rails:install_errors_controller
57
63
 
58
64
  # API resource generator
59
65
  rails generate auxiliary_rails:api_resource
60
66
 
61
67
  # Command generator
62
68
  rails generate auxiliary_rails:command
69
+
70
+ # Service generator
71
+ rails generate auxiliary_rails:service
72
+ ```
73
+
74
+ ### API Resources
75
+
76
+ Read article [Building an API](https://github.com/ergoserv/handbook/blob/master/guides/building_api.md) for more details.
77
+
78
+ Use generator to generate appropriate classes and files (Resource, Entity, Helper, Spec) for the specified end-point:
79
+
80
+ ```sh
81
+ rails generate auxiliary_rails:api_resource
82
+ ```
83
+
84
+ ## Application
85
+
86
+ ### Command Objects
87
+
88
+ Variation of implementation of [Command pattern](https://refactoring.guru/design-patterns/command).
89
+
90
+ Read post [Command Objects - a.k.a Service Objects in Ruby on Rails - The Ergonomic Way](https://www.ergoserv.com/blog/command-objects-aka-service-objects-in-ruby-on-rails-the-ergonomic-way) for more details.
91
+
92
+ ```ruby
93
+ # app/commands/application_command.rb
94
+ class ApplicationCommand < AuxiliaryRails::Application::Command
95
+ end
96
+
97
+ # app/commands/register_user_command.rb
98
+ class RegisterUserCommand < ApplicationCommand
99
+ # Define command arguments
100
+ # using `param` or `option` methods provided by dry-initializer
101
+ # https://dry-rb.org/gems/dry-initializer/3.0/
102
+ param :email
103
+ param :password
104
+
105
+ # Define the results of the command using `attr_reader`
106
+ # and set it as a regular instance var inside the command
107
+ attr_reader :user
108
+
109
+ # Regular Active Model Validations can be used to validate params
110
+ # https://api.rubyonrails.org/classes/ActiveModel/Validations.html
111
+ # Use #valid?, #invalid?, #validate! methods to engage validations
112
+ validates :password, length: { in: 8..32 }
113
+
114
+ # Define the only public method `#perform` where command's flow is defined
115
+ def perform
116
+ # Use `return failure!` and `return success!` inside `#perform` method
117
+ # to control exits from the command with appropriate status.
118
+
119
+ # Use `return failure!` to exit from the command with failure
120
+ return failure! if registration_disabled?
121
+
122
+ # Method `#transaction` is a shortcut for `ActiveRecord::Base.transaction`
123
+ transaction do
124
+ # Keep the `#perform` method short and clean, put all the steps, actions
125
+ # and business logic into meaningful and self-explanatory methods
126
+ @user = create_user
127
+
128
+ # Use `error!` method to interrupt the flow raising an error
129
+ error! unless user.persistent?
130
+
131
+ send_notifications
132
+ # ...
133
+ end
134
+
135
+ # Always end the `#perform` method with `success!`.
136
+ # It will set the proper command's execution status.
137
+ success!
138
+ end
139
+
140
+ private
141
+
142
+ def create_user
143
+ User.create(email: email, password: password)
144
+ end
145
+
146
+ def send_notifications
147
+ # ...
148
+ end
149
+ end
150
+
151
+ ### usage ###
152
+
153
+ class RegistrationsController
154
+ def register
155
+ cmd = RegisterUserCommand.call(params[:email], params[:password])
156
+
157
+ if cmd.success?
158
+ redirect_to user_path(cmd.user) and return
159
+ else
160
+ @errors = cmd.errors
161
+ end
162
+
163
+ ### OR ###
164
+
165
+ RegisterUserCommand.call(params[:email], params[:password])
166
+ .on(:success) do
167
+ redirect_to dashboard_path and return
168
+ end
169
+ .on(:failure) do |cmd|
170
+ @errors = cmd.errors
171
+ end
172
+ end
173
+ end
174
+ ```
175
+
176
+ ### Error Objects
177
+
178
+ Custom error objects.
179
+ Read article [Error Handling](https://github.com/ergoserv/handbook/blob/master/guides/error_handling.md) for more details.
180
+
181
+ ```ruby
182
+ # app/errors/application_error.rb
183
+ class ApplicationCommand < AuxiliaryRails::Application::Error
184
+ end
185
+ ```
186
+
187
+ ### Form Objects
188
+
189
+ ```ruby
190
+ # app/forms/application_form.rb
191
+ class ApplicationForm < AuxiliaryRails::Application::Form
192
+ end
193
+
194
+ # app/forms/company_registration_form.rb
195
+ class CompanyRegistrationForm < ApplicationForm
196
+ # Define form attributes
197
+ attribute :company_name, :string
198
+ attribute :email, :string
199
+
200
+ # Define form submission results
201
+ attr_reader :company
202
+
203
+ # Regular Active Model Validations can be used to validate attributes
204
+ # https://api.rubyonrails.org/classes/ActiveModel/Validations.html
205
+ validates :company_name, presence: true
206
+ validates :email, email: true
207
+
208
+ def perform
209
+ # Perform business logic here
210
+
211
+ # Use `attr_reader` to expose the submission results.
212
+ @company = create_company
213
+ # Return `failure!` to indicate failure and stop execution
214
+ return failure! if @company.invalid?
215
+
216
+ send_notification if email.present?
217
+
218
+ # Always end with `success!` method call to indicate success
219
+ success!
220
+ end
221
+
222
+ private
223
+
224
+ def create_comany
225
+ Company.create(name: company_name)
226
+ end
227
+
228
+ def send_notification
229
+ # mail to: email
230
+ end
231
+ end
232
+
233
+ ### Usage ###
234
+
235
+ form = CompanyRegistrationForm.call(params[:company])
236
+ if form.success?
237
+ redirect_to company_path(form.company) and return
238
+ else
239
+ @errors = form.errors
240
+ end
241
+ ```
242
+
243
+ ### Query Objects
244
+
245
+ ```ruby
246
+ # app/queries/application_query.rb
247
+ class ApplicationQuery < AuxiliaryRails::Application::Query
248
+ end
249
+
250
+ # app/queries/authors_query.rb
251
+ class AuthorsQuery < ApplicationQuery
252
+ default_relation Author.all
253
+
254
+ option :name_like, optional: true
255
+ option :with_books, optional: true
256
+
257
+ def perform
258
+ if recent == true
259
+ # equivalent to `@query = @query.order(:created_at)`:
260
+ query order(:created_at)
261
+ end
262
+
263
+ if name_like.present?
264
+ query with_name_like(name_like)
265
+ end
266
+ end
267
+
268
+ private
269
+
270
+ def with_name_like(value)
271
+ where('authors.name LIKE ?', "%#{value}%")
272
+ end
273
+ end
274
+
275
+ # app/queries/authors_with_books_query.rb
276
+ class AuthorsWithBooksQuery < AuthorsQuery
277
+ option :min_book_count, default: { 3 }
278
+
279
+ def perform
280
+ query joins(:books)
281
+ .group(:author_id)
282
+ .having('COUNT(books.id) > ?', min_book_count)
283
+ end
284
+ end
285
+
286
+ ### Usage ###
287
+
288
+ # it is possible to wrap query object in a scope and use as a regular scope
289
+ # app/models/author.rb
290
+ class Author < ApplicationRecord
291
+ scope :name_like, ->(value) { AuthorsQuery.call(name_like: value) }
292
+ end
293
+
294
+ authors = Author.name_like('Arthur')
295
+
296
+ # or call query directly
297
+ authors = AuthorsWithBooksQuery.call(min_book_count: 10)
298
+ ```
299
+
300
+ ### Service Modules
301
+
302
+ Read [Service Modules](https://github.com/ergoserv/handbook/blob/master/guides/service_modules.md) for more details.
303
+
304
+ **Service Generator**
305
+
306
+ ```sh
307
+ rails generate auxiliary_rails:service
308
+ ```
309
+
310
+ **Service Config** - provides a unified access to a service configs and loads the first found from:
311
+
312
+ - Constant (`MyService::CONFIG`)
313
+ - Application config file (`config/settings.yml`, see gem [`config`](https://github.com/rubyconfig/config))
314
+ - Service config file (`config/services/my_service.yml`)
315
+
316
+ ```ruby
317
+ # app/services/my_service.rb
318
+ module MyService
319
+ extend AuxiliaryRails::Application::Service
320
+ end
321
+
322
+ # usage
323
+ MyService.config.some_key
63
324
  ```
64
325
 
65
326
  ### View Helpers
@@ -67,6 +328,7 @@ rails generate auxiliary_rails:command
67
328
  ```ruby
68
329
  current_controller?(*ctrl_names)
69
330
  current_action?(*action_names)
331
+ display_name(resource)
70
332
  ```
71
333
 
72
334
  ## Development