rails-add_ons 0.2.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +24 -0
- data/app/assets/config/rails_add_ons_manifest.js +0 -0
- data/app/assets/javascripts/rails/add_ons/application/widgets.js.coffee +48 -0
- data/app/assets/javascripts/rails/add_ons/application.js +17 -0
- data/app/assets/javascripts/rails_add_ons.js +1 -0
- data/app/assets/stylesheets/rails/add_ons/application/bootstrap_overrides.scss +3 -0
- data/app/assets/stylesheets/rails/add_ons/application/table_monospaced.scss +3 -0
- data/app/assets/stylesheets/rails/add_ons/application/widgets.scss +5 -0
- data/app/assets/stylesheets/rails/add_ons/application.scss +4 -0
- data/app/assets/stylesheets/rails/add_ons/bootstrap_v3_flex_extension.scss +13 -0
- data/app/assets/stylesheets/rails/add_ons/font_awesome.css +3 -0
- data/app/assets/stylesheets/rails_add_ons.css +3 -0
- data/app/caches/api/cache.rb +24 -0
- data/app/components/component/base.rb +24 -0
- data/app/components/component/collection_table.rb +80 -0
- data/app/components/component/resource_table.rb +25 -0
- data/app/concerns/api_controller_concerns/exception_handling.rb +24 -0
- data/app/concerns/resources_controller/pagination.rb +15 -0
- data/app/concerns/resources_controller/sorting.rb +15 -0
- data/app/controllers/api/resources_controller/base.rb +254 -0
- data/app/controllers/api/service_controller/base.rb +73 -0
- data/app/controllers/rails/add_ons/widgets_controller.rb +10 -0
- data/app/controllers/resources_controller/base.rb +180 -0
- data/app/controllers/service_controller/base.rb +135 -0
- data/app/extensions/object_extensions.rb +8 -0
- data/app/helpers/rails/add_ons/table_helper.rb +50 -0
- data/app/helpers/rails/add_ons/widget_helper.rb +10 -0
- data/app/parsers/api/resources_controller/condition_parser.rb +65 -0
- data/app/services/rails/add_ons/service/base.rb +156 -0
- data/app/services/rails/add_ons/service/result/base.rb +25 -0
- data/app/views/component/_collection_table.haml +20 -0
- data/app/views/component/_resource_table.haml +15 -0
- data/app/views/frontend/_navbar.haml +23 -0
- data/app/views/layouts/rails/add_ons/application.haml +23 -0
- data/app/views/resources_controller/base/_after_show_table.haml +0 -0
- data/app/views/resources_controller/base/_before_show_table.haml +0 -0
- data/app/views/resources_controller/base/_form.haml +2 -0
- data/app/views/resources_controller/base/_form_buttons.haml +4 -0
- data/app/views/resources_controller/base/_form_errors.haml +6 -0
- data/app/views/resources_controller/base/_pagination.haml +4 -0
- data/app/views/resources_controller/base/_show.haml +2 -0
- data/app/views/resources_controller/base/_show_actions.haml +6 -0
- data/app/views/resources_controller/base/_table.haml +2 -0
- data/app/views/resources_controller/base/_table_actions.haml +12 -0
- data/app/views/resources_controller/base/edit.haml +6 -0
- data/app/views/resources_controller/base/index.haml +13 -0
- data/app/views/resources_controller/base/new.haml +6 -0
- data/app/views/resources_controller/base/show.haml +10 -0
- data/app/views/service_controller/base/_create_after_service_output.haml +0 -0
- data/app/views/service_controller/base/_create_before_service_output.haml +0 -0
- data/app/views/service_controller/base/_form_buttons.haml +2 -0
- data/app/views/service_controller/base/_form_errors.haml +6 -0
- data/app/views/service_controller/base/create.haml +14 -0
- data/app/views/service_controller/base/new.haml +6 -0
- data/app/views/widget/base/_remote_load_code.html.erb +4 -0
- data/app/views/widget/base/_widget_controls.haml +3 -0
- data/app/views/widget/render.js.erb +0 -0
- data/app/widgets/widget/base.rb +92 -0
- data/config/initializers/assets.rb +7 -0
- data/config/initializers/extend_object.rb +1 -0
- data/config/locales/de.yml +39 -0
- data/config/locales/en.yml +39 -0
- data/config/routes.rb +5 -0
- data/lib/rails/add_ons/engine.rb +7 -0
- data/lib/rails/add_ons/version.rb +5 -0
- data/lib/rails/add_ons.rb +7 -0
- data/lib/rails-add_ons.rb +8 -0
- data/lib/tasks/rails/add_ons_tasks.rake +4 -0
- metadata +268 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module Api
|
2
|
+
module ServiceController
|
3
|
+
class Base < ::ApiController
|
4
|
+
module RestActions
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include ActionController::MimeResponds
|
9
|
+
|
10
|
+
respond_to :json
|
11
|
+
|
12
|
+
if respond_to?(:before_action)
|
13
|
+
before_action :initialize_service_for_create, only: [:create]
|
14
|
+
else
|
15
|
+
before_filter :initialize_service_for_create, only: [:create]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
@result = @service.perform
|
21
|
+
respond_to do |format|
|
22
|
+
if @result.success?
|
23
|
+
format.json { render json: serialize_result(@result), status: :created }
|
24
|
+
else
|
25
|
+
format.json { render json: { errors: serialize_errors(@result.errors) }, status: 422 }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def initialize_service_for_create
|
33
|
+
# In rails 5 permitted_params is an instance of ActionController::Parameters.
|
34
|
+
# Stragely, when calling #delete on it, it does not delete the key, so we have
|
35
|
+
# to transform it into a hash first.
|
36
|
+
params_hash = permitted_params.try(:to_h).presence || permitted_params
|
37
|
+
|
38
|
+
options = params_hash.try(:delete, :options) || {}
|
39
|
+
@service = service_class.new(params_hash, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def permitted_params
|
43
|
+
raise "not implemented"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Service
|
48
|
+
extend ActiveSupport::Concern
|
49
|
+
|
50
|
+
def service_class
|
51
|
+
self.class.service_class
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module Serialization
|
56
|
+
private
|
57
|
+
|
58
|
+
def serialize_result(result)
|
59
|
+
result.as_json
|
60
|
+
end
|
61
|
+
|
62
|
+
def serialize_errors(errors)
|
63
|
+
errors
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
include RestActions
|
68
|
+
include Service
|
69
|
+
include Serialization
|
70
|
+
include ApiControllerConcerns::ExceptionHandling
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module ResourcesController
|
2
|
+
class Base < ::FrontendController
|
3
|
+
layout 'rails/add_ons/application'
|
4
|
+
|
5
|
+
module RestActions
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ActionController::MimeResponds
|
10
|
+
|
11
|
+
respond_to :html
|
12
|
+
responders :flash
|
13
|
+
|
14
|
+
if respond_to?(:before_action)
|
15
|
+
before_action :load_collection, only: [:index]
|
16
|
+
before_action :load_resource, only: [:show, :edit, :destroy, :update]
|
17
|
+
before_action :initialize_resource, only: [:new]
|
18
|
+
before_action :initialize_resource_for_create, only: [:create]
|
19
|
+
else
|
20
|
+
before_filter :load_collection, only: [:index]
|
21
|
+
before_filter :load_resource, only: [:show, :edit, :destroy, :update]
|
22
|
+
before_filter :initialize_resource, only: [:new]
|
23
|
+
before_filter :initialize_resource_for_create, only: [:create]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def index; end
|
28
|
+
def new; end
|
29
|
+
def show; end
|
30
|
+
def edit; end
|
31
|
+
|
32
|
+
def update
|
33
|
+
if Rails::VERSION::MAJOR < 4
|
34
|
+
@resource.update_attributes(permitted_params)
|
35
|
+
else
|
36
|
+
@resource.update(permitted_params)
|
37
|
+
end
|
38
|
+
respond_with @resource
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy
|
42
|
+
@resource.destroy
|
43
|
+
respond_with @resource
|
44
|
+
end
|
45
|
+
|
46
|
+
def create
|
47
|
+
@resource.save
|
48
|
+
respond_with @resource
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def after_create_location
|
54
|
+
->(controller) { resource_path(@resource) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_collection_scope
|
58
|
+
resource_class
|
59
|
+
end
|
60
|
+
def load_collection
|
61
|
+
@collection = load_collection_scope.all
|
62
|
+
end
|
63
|
+
|
64
|
+
def load_resource_scope
|
65
|
+
resource_class
|
66
|
+
end
|
67
|
+
def load_resource
|
68
|
+
@resource = load_resource_scope.find(params[:id])
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize_resource
|
72
|
+
@resource = resource_class.new
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize_resource_for_create
|
76
|
+
@resource = resource_class.new(permitted_params)
|
77
|
+
end
|
78
|
+
|
79
|
+
def permitted_params
|
80
|
+
raise "not implemented"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module Resources
|
85
|
+
extend ActiveSupport::Concern
|
86
|
+
|
87
|
+
included do
|
88
|
+
helper_method :resource_class
|
89
|
+
end
|
90
|
+
|
91
|
+
def resource_class
|
92
|
+
self.class.resource_class
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
module RestResourceUrls
|
97
|
+
extend ActiveSupport::Concern
|
98
|
+
|
99
|
+
included do
|
100
|
+
helper_method :new_resource_path
|
101
|
+
helper_method :collection_path
|
102
|
+
helper_method :resource_path
|
103
|
+
helper_method :edit_resource_path
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def new_resource_path
|
109
|
+
url_for(action: :new, only_path: true)
|
110
|
+
end
|
111
|
+
|
112
|
+
def collection_path
|
113
|
+
url_for(action: :index, only_path: true)
|
114
|
+
end
|
115
|
+
|
116
|
+
def resource_path(resource)
|
117
|
+
url_for(action: :show, id: resource, only_path: true)
|
118
|
+
end
|
119
|
+
|
120
|
+
def edit_resource_path(resource)
|
121
|
+
url_for(action: :edit, id: resource, only_path: true)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
module ResourceInflections
|
126
|
+
extend ActiveSupport::Concern
|
127
|
+
|
128
|
+
included do
|
129
|
+
helper_method :inflections
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def inflections
|
135
|
+
{
|
136
|
+
resource_name: resource_class.model_name.human(count: 1),
|
137
|
+
collection_name: resource_class.model_name.human(count: 2)
|
138
|
+
}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
module LocationHistory
|
143
|
+
extend ActiveSupport::Concern
|
144
|
+
|
145
|
+
included do
|
146
|
+
if respond_to?(:before_action)
|
147
|
+
before_action :store_location
|
148
|
+
else
|
149
|
+
before_filter :store_location
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def store_location
|
156
|
+
truncate_location_history(9)
|
157
|
+
location_history[Time.zone.now] = request.referer
|
158
|
+
end
|
159
|
+
|
160
|
+
def location_history
|
161
|
+
session[:location_history] ||= {}
|
162
|
+
end
|
163
|
+
|
164
|
+
def last_location
|
165
|
+
location_history.sort.last.try(:last)
|
166
|
+
end
|
167
|
+
|
168
|
+
def truncate_location_history(count = 0)
|
169
|
+
return if location_history.size <= count
|
170
|
+
session[:location_history] = session[:location_history].sort.last(count).to_h
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
include RestActions
|
175
|
+
include Resources
|
176
|
+
include RestResourceUrls
|
177
|
+
include ResourceInflections
|
178
|
+
include LocationHistory
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module ServiceController
|
2
|
+
class Base < ::FrontendController
|
3
|
+
layout 'rails/add_ons/application'
|
4
|
+
|
5
|
+
module RestActions
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ActionController::MimeResponds
|
10
|
+
|
11
|
+
respond_to :html
|
12
|
+
responders :flash
|
13
|
+
|
14
|
+
if respond_to?(:before_action)
|
15
|
+
before_action :initialize_service, only: [:new]
|
16
|
+
before_action :initialize_service_for_create, only: [:create]
|
17
|
+
else
|
18
|
+
before_filter :initialize_service, only: [:new]
|
19
|
+
before_filter :initialize_service_for_create, only: [:create]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def new; end
|
25
|
+
|
26
|
+
def create
|
27
|
+
@response = @resource.perform
|
28
|
+
if @response.success?
|
29
|
+
render :create
|
30
|
+
else
|
31
|
+
render :new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def initialize_service
|
38
|
+
@resource = service_class.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize_service_for_create
|
42
|
+
@resource = service_class.new(permitted_params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def permitted_params
|
46
|
+
raise "not implemented"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module Service
|
51
|
+
extend ActiveSupport::Concern
|
52
|
+
|
53
|
+
included do
|
54
|
+
helper_method :service_class
|
55
|
+
end
|
56
|
+
|
57
|
+
def service_class
|
58
|
+
self.class.service_class
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module RestResourceUrls
|
63
|
+
extend ActiveSupport::Concern
|
64
|
+
|
65
|
+
included do
|
66
|
+
helper_method :new_resource_path
|
67
|
+
helper_method :create_resource_path
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def new_resource_path
|
73
|
+
url_for(action: :new, only_path: true)
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_resource_path
|
77
|
+
url_for(action: :create, only_path: true)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module ResourceInflections
|
82
|
+
extend ActiveSupport::Concern
|
83
|
+
|
84
|
+
included do
|
85
|
+
helper_method :inflections
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def inflections
|
91
|
+
{
|
92
|
+
service_name: service_class.model_name.human
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
module LocationHistory
|
98
|
+
extend ActiveSupport::Concern
|
99
|
+
|
100
|
+
included do
|
101
|
+
if respond_to?(:before_action)
|
102
|
+
before_action :store_location
|
103
|
+
else
|
104
|
+
before_filter :store_location
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def store_location
|
111
|
+
truncate_location_history(9)
|
112
|
+
location_history[Time.zone.now] = request.referer
|
113
|
+
end
|
114
|
+
|
115
|
+
def location_history
|
116
|
+
session[:location_history] ||= {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def last_location
|
120
|
+
location_history.sort.last.try(:last)
|
121
|
+
end
|
122
|
+
|
123
|
+
def truncate_location_history(count = 0)
|
124
|
+
return if location_history.size <= count
|
125
|
+
session[:location_history] = session[:location_history].sort.last(count).to_h
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
include Service
|
130
|
+
include RestActions
|
131
|
+
include RestResourceUrls
|
132
|
+
include ResourceInflections
|
133
|
+
include LocationHistory
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Rails
|
2
|
+
module AddOns
|
3
|
+
module TableHelper
|
4
|
+
def collection_table(options = {}, &block)
|
5
|
+
Component::CollectionTable.new(self, options, &block).perform
|
6
|
+
end
|
7
|
+
|
8
|
+
def resource_table(options = {}, &block)
|
9
|
+
Component::ResourceTable.new(self, options, &block).perform
|
10
|
+
end
|
11
|
+
|
12
|
+
def sort_link(column_name, title, options = {})
|
13
|
+
return title if options === false
|
14
|
+
SortLink.new(self, column_name, title, options).perform
|
15
|
+
end
|
16
|
+
|
17
|
+
class SortLink
|
18
|
+
def initialize(view_context, column_name, title, options)
|
19
|
+
default_options = {}
|
20
|
+
|
21
|
+
if options === true
|
22
|
+
@options = default_options
|
23
|
+
else
|
24
|
+
@options = options.reverse_merge(default_options)
|
25
|
+
end
|
26
|
+
|
27
|
+
@view_context = view_context
|
28
|
+
@column_name = column_name
|
29
|
+
@title = title
|
30
|
+
|
31
|
+
if h.params[:sort_direction].present?
|
32
|
+
@sort_direction = (h.params[:sort_direction].to_sym == :asc) ? :desc : :asc
|
33
|
+
else
|
34
|
+
@sort_direction = :asc
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def perform
|
39
|
+
h.link_to(@title, h.url_for(sort_by: @column_name, sort_direction: @sort_direction))
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def h
|
45
|
+
@view_context
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Api
|
2
|
+
module ResourcesController
|
3
|
+
class ConditionParser
|
4
|
+
OPERATOR_MAP = {
|
5
|
+
gt: :>,
|
6
|
+
gt_or_eq: :>=,
|
7
|
+
eq: :'=',
|
8
|
+
not_eq: :'<>',
|
9
|
+
lt_or_eq: :<=,
|
10
|
+
lt: :<
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(field, condition)
|
14
|
+
# @condition = { field => condition }
|
15
|
+
@field, @condition = field, condition
|
16
|
+
end
|
17
|
+
|
18
|
+
def condition_statement
|
19
|
+
build_condition_statement(@field, @condition)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def build_condition_statement(parent_key, condition, nested = false)
|
25
|
+
if is_a_condition?(parent_key) && !nested
|
26
|
+
column, operator = extract_column_and_operator(parent_key)
|
27
|
+
["#{column} = ?", condition]
|
28
|
+
else
|
29
|
+
if nested
|
30
|
+
column = extract_column(parent_key)
|
31
|
+
{ column => condition }
|
32
|
+
else
|
33
|
+
{ parent_key => build_condition_statement(condition.first[0], condition.first[1], true) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def is_a_condition?(obj)
|
39
|
+
!!extract_operator(obj)
|
40
|
+
end
|
41
|
+
|
42
|
+
def extract_operator(obj)
|
43
|
+
string = obj.to_s
|
44
|
+
operator_map.each do |key, value|
|
45
|
+
return value if string.end_with?("(#{key})")
|
46
|
+
end
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_column(obj)
|
51
|
+
obj.to_s.split("(").first
|
52
|
+
end
|
53
|
+
|
54
|
+
def extract_column_and_operator(string)
|
55
|
+
if string =~ /([a-z_]{1,})\(([a-z_]{2,})\)/
|
56
|
+
return $~[1], $~[2]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def operator_map
|
61
|
+
OPERATOR_MAP
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Rails
|
2
|
+
module AddOns
|
3
|
+
module Service
|
4
|
+
class Base
|
5
|
+
include ActiveModel::Model
|
6
|
+
|
7
|
+
def self.attr_accessor(*args)
|
8
|
+
super
|
9
|
+
add_attribute_names(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.add_attribute_names(*args)
|
13
|
+
args.each do |attr_name|
|
14
|
+
attribute_names << attr_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.attribute_names
|
19
|
+
(@attr_names ||= [])
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.i18n_scope
|
23
|
+
:activerecord
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.call(*args)
|
27
|
+
new(*args).perform
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(attributes = {}, options = {}, &block)
|
31
|
+
@options = options
|
32
|
+
@block = block
|
33
|
+
@attributes = {}
|
34
|
+
set_attributes(attributes)
|
35
|
+
initialize_result
|
36
|
+
initialize_errors
|
37
|
+
initialize_messages
|
38
|
+
after_initialize
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
module Attributes
|
44
|
+
def set_attributes(attributes)
|
45
|
+
attributes.each do |key, value|
|
46
|
+
send("#{key}=", value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
include Attributes
|
52
|
+
|
53
|
+
module Callbacks
|
54
|
+
def after_initialize; end
|
55
|
+
def before_perform; end
|
56
|
+
def after_perform; end
|
57
|
+
def before_validation; end
|
58
|
+
def after_validation; end
|
59
|
+
def after_perform; end
|
60
|
+
|
61
|
+
def perform
|
62
|
+
before_validation
|
63
|
+
return perform_result unless valid?
|
64
|
+
after_validation
|
65
|
+
before_perform
|
66
|
+
say "Performing" do
|
67
|
+
_perform
|
68
|
+
end
|
69
|
+
after_perform
|
70
|
+
perform_result
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
module Resultable
|
75
|
+
private
|
76
|
+
|
77
|
+
def initialize_result
|
78
|
+
@result = result_class.new
|
79
|
+
end
|
80
|
+
|
81
|
+
def perform_result
|
82
|
+
copy_messages_to_result
|
83
|
+
copy_errors_to_result
|
84
|
+
@result
|
85
|
+
end
|
86
|
+
|
87
|
+
def result_class
|
88
|
+
"#{self.class.name}::Result".constantize
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module Errors
|
93
|
+
private
|
94
|
+
|
95
|
+
def initialize_errors
|
96
|
+
@errors = ActiveModel::Errors.new(self)
|
97
|
+
end
|
98
|
+
|
99
|
+
def copy_errors_to_result
|
100
|
+
@result.instance_variable_set(:@errors, @errors)
|
101
|
+
end
|
102
|
+
|
103
|
+
def copy_errors_from_to(obj, key_prefix)
|
104
|
+
obj.errors.each do |key, message|
|
105
|
+
@errors.add(key_prefix, message)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
module Messages
|
111
|
+
private
|
112
|
+
|
113
|
+
def initialize_messages
|
114
|
+
@messages = []
|
115
|
+
end
|
116
|
+
|
117
|
+
def say(what, &block)
|
118
|
+
@indent ||= 0
|
119
|
+
if block_given?
|
120
|
+
@indent += 1
|
121
|
+
output "#{output_prefix}#{(" " * @indent)}#{what}..."
|
122
|
+
block_result = yield
|
123
|
+
say_done
|
124
|
+
@indent -= 1
|
125
|
+
block_result
|
126
|
+
else
|
127
|
+
output "#{output_prefix}#{(" " * @indent)}#{what}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def say_done
|
132
|
+
say " => Done"
|
133
|
+
end
|
134
|
+
|
135
|
+
def output_prefix
|
136
|
+
"[#{self.class.name}] "
|
137
|
+
end
|
138
|
+
|
139
|
+
def output(what)
|
140
|
+
@messages << what
|
141
|
+
puts what
|
142
|
+
end
|
143
|
+
|
144
|
+
def copy_messages_to_result
|
145
|
+
@result.instance_variable_set(:@messages, @messages)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
include Errors
|
150
|
+
include Resultable
|
151
|
+
include Callbacks
|
152
|
+
include Messages
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rails
|
2
|
+
module AddOns
|
3
|
+
module Service::Result
|
4
|
+
class Base
|
5
|
+
attr_reader :messages, :errors
|
6
|
+
|
7
|
+
module Succeedable
|
8
|
+
def success?
|
9
|
+
!failed?
|
10
|
+
end
|
11
|
+
|
12
|
+
def failed?
|
13
|
+
@errors.any?
|
14
|
+
end
|
15
|
+
|
16
|
+
def ok?
|
17
|
+
success?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include Succeedable
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|