rails_use_case 0.0.1 → 0.0.3
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 +4 -4
- data/README.md +124 -3
- data/lib/rails/use_case.rb +12 -26
- data/lib/rails_use_case.rb +1 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eccdc9b039ad948018925576475a8857da769828aef5f58f2426901b6cca77c3
|
4
|
+
data.tar.gz: 5ed1d23accbd83dda0428d7fc3f959366e49e5a2cb29e95ec1e641f1063d8942
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 931eb6a75e1d92604c5f1e33140a3ddd3c20f6cbad225814f4d6e75e801e95f09d3a738d778643221f29b82f2c188c2c007e4449313297bacfee4eacd41bacd2
|
7
|
+
data.tar.gz: aa4cc82f951293c672211129cdf27968bca51a218305982c55929b13ba5cafd9b60edcce5b89824b6ba4108ad0c8ec8dc3dbed6d06cc841ea04d0a4ed4b2aa1d
|
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Rails Use Case gem
|
2
2
|
|
3
|
-
Opinionated gem for UseCases and Services in rails.
|
3
|
+
Opinionated gem for UseCases and Services in rails to keep models and controllers slim.
|
4
|
+
|
5
|
+
The purpose of a UseCase is to contain reusable high level business logic which would normally be
|
6
|
+
located in the controller. Examples are: Place an item in the cart, create a new user or delete a comment.
|
7
|
+
|
8
|
+
The purpose of a Service is to contain low level non-domain code like communication with a API,
|
9
|
+
generating an export, upload via FTP or generating a PDF.
|
4
10
|
|
5
11
|
|
6
12
|
## Setup
|
@@ -10,9 +16,124 @@ gem 'rails_use_case'
|
|
10
16
|
```
|
11
17
|
|
12
18
|
|
13
|
-
##
|
19
|
+
## Use Case
|
20
|
+
|
21
|
+
The purpose of a UseCase is to contain reusable high level business logic which would normally be
|
22
|
+
located in the controller. It defines a process via `step` definitions. A UseCase takes params
|
23
|
+
and has a outcome, which is successfully or failed. It doesn't have a configuration file and doesn't
|
24
|
+
log anything. Examples are: Place an item in the cart, create a new user or delete a comment.
|
25
|
+
|
26
|
+
Steps are executed in the defined order. Only when a step succeeds (returns true) the next step will
|
27
|
+
be executed. Steps can be skipped via `if` and `unless`.
|
28
|
+
|
29
|
+
The UseCase should assign the main record to `@record`. Calling save! without argument will try to
|
30
|
+
save that record or raises an exception. Also the `@record` will automatically passed into the outcome.
|
31
|
+
|
32
|
+
The params should always passed as hash and are automatically assigned to instance variables.
|
33
|
+
|
34
|
+
### Example UseCase
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class CreateBlogPost < Rails::UseCase
|
38
|
+
attr_accessor :title, :content, :author, :skip_notifications
|
39
|
+
|
40
|
+
validates :title, presence: true
|
41
|
+
validates :content, presence: true
|
42
|
+
validates :author, presence: true
|
43
|
+
|
44
|
+
step :build_post
|
45
|
+
step :save!
|
46
|
+
step :notify_subscribers, unless: -> { skip_notifications }
|
47
|
+
|
48
|
+
|
49
|
+
private def build_post
|
50
|
+
@record = BlogPost.new(
|
51
|
+
title: title,
|
52
|
+
content: content,
|
53
|
+
created_by: author,
|
54
|
+
type: :default
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
private def notify_subscribers
|
59
|
+
# ... send some mails ...
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
Example usage of that UseCase:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
result = CreateBlogPost.perform(
|
68
|
+
title: 'Super Awesome Stuff!',
|
69
|
+
content: 'Lorem Ipsum Dolor Sit Amet',
|
70
|
+
created_by: current_user,
|
71
|
+
skip_notifications: false
|
72
|
+
)
|
73
|
+
|
74
|
+
puts result.inspect
|
75
|
+
# => {
|
76
|
+
# success: true,
|
77
|
+
# record: BlogPost(...)
|
78
|
+
# errors: [],
|
79
|
+
# error: nil
|
80
|
+
# }
|
81
|
+
```
|
82
|
+
|
83
|
+
|
84
|
+
## Service
|
85
|
+
|
86
|
+
The purpose of a Service is to contain low level non-domain code like communication with a API,
|
87
|
+
generating an export, upload via FTP or generating a PDF. It takes params, has it's own configuration
|
88
|
+
and writes a log file.
|
89
|
+
|
90
|
+
It comes with call style invocation: `PDFGenerationService.(some, params)`
|
91
|
+
|
92
|
+
### Example Service
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
class PDFGenerationService < Rails::Service
|
96
|
+
attr_reader :pdf_template, :values
|
97
|
+
|
98
|
+
# Constructor.
|
99
|
+
def initialize
|
100
|
+
super 'pdf_generation'
|
101
|
+
prepare
|
102
|
+
validate_libreoffice
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Entry point.
|
107
|
+
#
|
108
|
+
# @param [PdfTemplate] pdf_template PdfTemplate record.
|
109
|
+
# @param [Hash<String, String>] values Mapping of variables to their values.
|
110
|
+
#
|
111
|
+
# @returns [String] Path to PDF file.
|
112
|
+
def call(pdf_template, values = {})
|
113
|
+
@pdf_template = pdf_template
|
114
|
+
@values = prepare_variable_values(values)
|
115
|
+
|
116
|
+
write_odt_file
|
117
|
+
replace_variables
|
118
|
+
generate_pdf
|
119
|
+
|
120
|
+
@pdf_file_path
|
121
|
+
ensure
|
122
|
+
delete_tempfile
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
### Configuration
|
128
|
+
|
129
|
+
The service tries to automatically load a configuration from `config/services/[service_name].yml`
|
130
|
+
which is available via the `config` method.
|
131
|
+
|
132
|
+
|
133
|
+
### Logging
|
14
134
|
|
15
|
-
|
135
|
+
The service los to a separate log file `log/services/[service_name].log`. You can write additional
|
136
|
+
logs via `logger.info(msg)`.
|
16
137
|
|
17
138
|
|
18
139
|
## License
|
data/lib/rails/use_case.rb
CHANGED
@@ -1,35 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_model
|
3
|
+
require 'active_model'
|
4
4
|
require 'rails/use_case/outcome'
|
5
5
|
|
6
6
|
module Rails
|
7
|
-
#
|
8
|
-
|
9
|
-
#
|
10
|
-
# The difference to a Service is that a Service contains low level
|
11
|
-
# non-domain code like communication with a API, generating an
|
12
|
-
# export, etc., while a UseCase contains high level domain logic
|
13
|
-
# like placing a item in the cart, submitting an order, etc.
|
14
|
-
#
|
15
|
-
# The logic of a UseCase is defined via steps. The next step is only
|
16
|
-
# executed when the previous ones returned a truthy value.
|
17
|
-
#
|
18
|
-
# The UseCase should assign the main record to @record. Calling save!
|
19
|
-
# without argument will try to save that record or raises an exception.
|
20
|
-
#
|
21
|
-
# A UseCase should raise the UseCase::Error exception for any
|
22
|
-
# problems.
|
23
|
-
#
|
24
|
-
# UseCase also includes ActiveModel::Validations for simple yet
|
25
|
-
# powerful validations. The validations are run automatically as first step.
|
26
|
-
#
|
27
|
-
# A UseCase can be called via .call(params) or .perform(params) and
|
28
|
-
# always returns a instance of UseCase::Outcome. params should be a hash.
|
29
|
-
class Rails::UseCase
|
7
|
+
# UseCase. See README.
|
8
|
+
class UseCase
|
30
9
|
include Callable
|
31
10
|
include ActiveModel::Validations
|
32
11
|
|
12
|
+
attr_reader :record
|
13
|
+
|
33
14
|
class Error < StandardError; end
|
34
15
|
|
35
16
|
class << self
|
@@ -115,13 +96,18 @@ module Rails
|
|
115
96
|
# @param record [ApplicationModel] Record to save.
|
116
97
|
# @raises [UseCase::Error] When record can't be saved.
|
117
98
|
private def save!(record = nil)
|
118
|
-
|
99
|
+
if record.nil?
|
100
|
+
record = @record
|
101
|
+
name = :record
|
102
|
+
else
|
103
|
+
name = record.model_name.singular
|
104
|
+
end
|
119
105
|
|
120
106
|
return false unless record
|
121
107
|
return true if record.save
|
122
108
|
|
123
109
|
errors.add(
|
124
|
-
|
110
|
+
name,
|
125
111
|
:invalid,
|
126
112
|
message: record.errors.full_messages.join(', ')
|
127
113
|
)
|
data/lib/rails_use_case.rb
CHANGED