much-rails 0.1.0 → 0.2.1
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/lib/much-rails.rb +8 -0
- data/lib/much-rails/action/base_router.rb +33 -13
- data/lib/much-rails/action/controller.rb +24 -3
- data/lib/much-rails/action/router.rb +10 -2
- data/lib/much-rails/destroy_service.rb +42 -5
- data/lib/much-rails/layout.rb +29 -2
- data/lib/much-rails/records/validate_destroy.rb +23 -13
- data/lib/much-rails/save_service.rb +44 -7
- data/lib/much-rails/service_validation_errors.rb +41 -0
- data/lib/much-rails/version.rb +1 -1
- data/much-rails.gemspec +1 -1
- data/test/support/fake_action_controller.rb +1 -1
- data/test/unit/action/base_router_tests.rb +13 -10
- data/test/unit/action/controller_tests.rb +19 -46
- data/test/unit/action/router_tests.rb +23 -7
- data/test/unit/destroy_service_tests.rb +165 -21
- data/test/unit/layout_tests.rb +24 -18
- data/test/unit/much-rails_tests.rb +42 -1
- data/test/unit/records/always_destroyable_tests.rb +1 -1
- data/test/unit/records/not_destroyable_tests.rb +1 -1
- data/test/unit/records/validate_destroy_tests.rb +84 -4
- data/test/unit/save_service_tests.rb +180 -20
- data/test/unit/service_validation_errors_tests.rb +107 -0
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5a9113cb9c28d12b0bcffbf5df47f43c2efe956dcb3eae246643461029af788
|
4
|
+
data.tar.gz: 95d5050085a06b6b747217b61d04197972948de584f48125bad8c858896913dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9699a1c4fede48c47b4e7e47148a3dc256b0d3ee29d8b681041614719b9d734946fc001599704f26237637bacaf204013ed01b5c8ff72d3cbceeb049bb5ea407
|
7
|
+
data.tar.gz: c550915e3af0b1142e73ad28b60e2e6944f5d789e769bbc31dcd35f07ace0ed16ba1bb18f253b8392b53b363167da70b33539589448d73bc1e21992341748768
|
data/lib/much-rails.rb
CHANGED
@@ -46,6 +46,14 @@ module MuchRails
|
|
46
46
|
add_instance_config :action, method_name: :action
|
47
47
|
add_instance_config :layout, method_name: :layout
|
48
48
|
|
49
|
+
def add_save_service_validation_error(exception_class, &block)
|
50
|
+
MuchRails::SaveService::ValidationErrors.add(exception_class, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_destroy_service_validation_error(exception_class, &block)
|
54
|
+
MuchRails::DestroyService::ValidationErrors.add(exception_class, &block)
|
55
|
+
end
|
56
|
+
|
49
57
|
class ActionConfig
|
50
58
|
attr_accessor :namespace
|
51
59
|
attr_accessor :sanitized_exception_classes
|
@@ -19,6 +19,7 @@ class MuchRails::Action::BaseRouter
|
|
19
19
|
@request_type_set = RequestTypeSet.new
|
20
20
|
@url_set = URLSet.new(self)
|
21
21
|
@definitions = []
|
22
|
+
@defined_urls = []
|
22
23
|
|
23
24
|
@base_url = DEFAULT_BASE_URL
|
24
25
|
instance_exec(&(block || proc{}))
|
@@ -28,6 +29,10 @@ class MuchRails::Action::BaseRouter
|
|
28
29
|
self.class.url_class
|
29
30
|
end
|
30
31
|
|
32
|
+
def unrouted_urls
|
33
|
+
@url_set.urls - @defined_urls
|
34
|
+
end
|
35
|
+
|
31
36
|
def validate!
|
32
37
|
definitions.each do |definition|
|
33
38
|
definition.request_type_actions.each do |request_type_action|
|
@@ -240,15 +245,22 @@ class MuchRails::Action::BaseRouter
|
|
240
245
|
acc
|
241
246
|
end
|
242
247
|
|
243
|
-
|
244
|
-
.for_route(
|
248
|
+
add_definition(
|
249
|
+
Definition.for_route(
|
245
250
|
http_method: http_method,
|
246
251
|
url: url,
|
247
252
|
default_action_class_name: default_class_name,
|
248
253
|
request_type_actions: request_type_actions,
|
249
254
|
called_from: called_from,
|
250
|
-
)
|
251
|
-
|
255
|
+
),
|
256
|
+
)
|
257
|
+
end
|
258
|
+
|
259
|
+
def add_definition(definition)
|
260
|
+
@definitions << definition
|
261
|
+
@defined_urls << definition.url
|
262
|
+
|
263
|
+
definition
|
252
264
|
end
|
253
265
|
|
254
266
|
class RequestTypeSet
|
@@ -301,6 +313,10 @@ class MuchRails::Action::BaseRouter
|
|
301
313
|
@set.empty?
|
302
314
|
end
|
303
315
|
|
316
|
+
def urls
|
317
|
+
@set.values
|
318
|
+
end
|
319
|
+
|
304
320
|
def add(name, path)
|
305
321
|
url = @router.url_class.new(@router, path, name.to_sym)
|
306
322
|
key = url.name
|
@@ -406,35 +422,40 @@ class MuchRails::Action::BaseRouter
|
|
406
422
|
called_from:)
|
407
423
|
new(
|
408
424
|
http_method: http_method,
|
409
|
-
|
410
|
-
name: url.name,
|
425
|
+
url: url,
|
411
426
|
default_action_class_name: default_action_class_name,
|
412
427
|
request_type_actions: request_type_actions,
|
413
428
|
called_from: called_from,
|
414
429
|
)
|
415
430
|
end
|
416
431
|
|
417
|
-
attr_reader :http_method, :
|
432
|
+
attr_reader :http_method, :url, :default_params
|
418
433
|
attr_reader :default_action_class_name, :request_type_actions
|
419
434
|
attr_reader :called_from
|
420
435
|
|
421
436
|
def initialize(
|
422
437
|
http_method:,
|
423
|
-
|
424
|
-
name:,
|
438
|
+
url:,
|
425
439
|
default_action_class_name:,
|
426
440
|
request_type_actions:,
|
427
441
|
called_from:,
|
428
442
|
default_params: nil)
|
429
443
|
@http_method = http_method
|
430
|
-
@
|
431
|
-
@name = name
|
444
|
+
@url = url
|
432
445
|
@default_params = default_params || {}
|
433
446
|
@default_action_class_name = default_action_class_name
|
434
447
|
@request_type_actions = request_type_actions || []
|
435
448
|
@called_from = called_from
|
436
449
|
end
|
437
450
|
|
451
|
+
def name
|
452
|
+
@url.name
|
453
|
+
end
|
454
|
+
|
455
|
+
def path
|
456
|
+
@url.path
|
457
|
+
end
|
458
|
+
|
438
459
|
def has_default_action_class_name?
|
439
460
|
!@default_action_class_name.nil?
|
440
461
|
end
|
@@ -443,8 +464,7 @@ class MuchRails::Action::BaseRouter
|
|
443
464
|
return super unless other.is_a?(self.class)
|
444
465
|
|
445
466
|
@http_method == other.http_method &&
|
446
|
-
@
|
447
|
-
@name == other.name &&
|
467
|
+
@url == other.url &&
|
448
468
|
@default_params == other.default_params &&
|
449
469
|
@default_action_class_name ==
|
450
470
|
other.default_action_class_name &&
|
@@ -9,19 +9,26 @@ module MuchRails::Action; end
|
|
9
9
|
# MuchRails::Action::Controller defines the behaviors for controllers processing
|
10
10
|
# MuchRails::Actions.
|
11
11
|
module MuchRails::Action::Controller
|
12
|
+
DEFAULT_ACTION_CLASS_FORMAT = :any
|
13
|
+
|
12
14
|
include MuchRails::Mixin
|
13
15
|
|
14
16
|
mixin_included do
|
15
17
|
attr_reader :much_rails_action_class
|
16
18
|
|
17
|
-
before_action
|
19
|
+
before_action(
|
20
|
+
:require_much_rails_action_class,
|
21
|
+
only: MuchRails::Action::Router::CONTROLLER_CALL_ACTION_METHOD_NAME,
|
22
|
+
)
|
18
23
|
before_action :permit_all_much_rails_action_params
|
19
24
|
end
|
20
25
|
|
21
26
|
mixin_instance_methods do
|
22
|
-
define_method(
|
27
|
+
define_method(
|
28
|
+
MuchRails::Action::Router::CONTROLLER_CALL_ACTION_METHOD_NAME,
|
29
|
+
) do
|
23
30
|
respond_to do |format|
|
24
|
-
format.public_send(
|
31
|
+
format.public_send(much_rails_action_class_format) do
|
25
32
|
result =
|
26
33
|
much_rails_action_class.call(
|
27
34
|
params: much_rails_action_params,
|
@@ -33,10 +40,24 @@ module MuchRails::Action::Controller
|
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
43
|
+
define_method(
|
44
|
+
MuchRails::Action::Router::CONTROLLER_NOT_FOUND_METHOD_NAME,
|
45
|
+
) do
|
46
|
+
respond_to do |format|
|
47
|
+
format.html do
|
48
|
+
head :not_found
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
36
53
|
def much_rails_action_class_name
|
37
54
|
"::#{params[MuchRails::Action::Router::ACTION_CLASS_PARAM_NAME]}"
|
38
55
|
end
|
39
56
|
|
57
|
+
def much_rails_action_class_format
|
58
|
+
much_rails_action_class.format || DEFAULT_ACTION_CLASS_FORMAT
|
59
|
+
end
|
60
|
+
|
40
61
|
def much_rails_action_params
|
41
62
|
# If a `params_root` value is specified, pull the params from that key and
|
42
63
|
# merge them into the base params.
|
@@ -7,7 +7,8 @@ module MuchRails::Action; end
|
|
7
7
|
|
8
8
|
class MuchRails::Action::Router < MuchRails::Action::BaseRouter
|
9
9
|
DEFAULT_CONTROLLER_NAME = "application"
|
10
|
-
|
10
|
+
CONTROLLER_CALL_ACTION_METHOD_NAME = :much_rails_call_action
|
11
|
+
CONTROLLER_NOT_FOUND_METHOD_NAME = :much_rails_not_found
|
11
12
|
ACTION_CLASS_PARAM_NAME = :much_rails_action_class_name
|
12
13
|
|
13
14
|
def self.url_class
|
@@ -48,7 +49,8 @@ class MuchRails::Action::Router < MuchRails::Action::BaseRouter
|
|
48
49
|
# end
|
49
50
|
def apply_to(application_routes_draw_scope)
|
50
51
|
validate!
|
51
|
-
|
52
|
+
draw_url_to = "#{controller_name}##{CONTROLLER_NOT_FOUND_METHOD_NAME}"
|
53
|
+
draw_route_to = "#{controller_name}##{CONTROLLER_CALL_ACTION_METHOD_NAME}"
|
52
54
|
|
53
55
|
definitions.each do |definition|
|
54
56
|
definition.request_type_actions.each do |request_type_action|
|
@@ -78,6 +80,12 @@ class MuchRails::Action::Router < MuchRails::Action::BaseRouter
|
|
78
80
|
}),
|
79
81
|
)
|
80
82
|
end
|
83
|
+
|
84
|
+
# Draw each URL that doesn't have a route definition so that we can generate
|
85
|
+
# them using MuchRails::RailsRoutes.
|
86
|
+
unrouted_urls.each do |url|
|
87
|
+
application_routes_draw_scope.get(url.path, to: draw_url_to, as: url.name)
|
88
|
+
end
|
81
89
|
end
|
82
90
|
alias_method :draw, :apply_to
|
83
91
|
|
@@ -18,12 +18,49 @@ module MuchRails::DestroyService
|
|
18
18
|
|
19
19
|
around_call do |receiver|
|
20
20
|
receiver.call
|
21
|
-
rescue MuchRails::
|
21
|
+
rescue *MuchRails::DestroyService::ValidationErrors.exception_classes => ex
|
22
22
|
set_the_return_value_for_the_call_method(
|
23
|
-
MuchRails::
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
MuchRails::DestroyService::ValidationErrors.result_for(ex),
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ValidationErrors
|
29
|
+
def self.add(exception_class, &block)
|
30
|
+
service_validation_errors.add(exception_class, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.exception_classes
|
34
|
+
service_validation_errors.exception_classes
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.result_for(ex)
|
38
|
+
service_validation_errors.result_for(ex)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.service_validation_errors
|
42
|
+
@service_validation_errors ||=
|
43
|
+
MuchRails::ServiceValidationErrors
|
44
|
+
.new
|
45
|
+
.tap do |e|
|
46
|
+
e.add(MuchRails::Records::DestructionInvalid) do |ex|
|
47
|
+
MuchRails::DestroyService::FailureResult.new(
|
48
|
+
record: ex.record,
|
49
|
+
exception: ex,
|
50
|
+
validation_errors: ex.errors.to_h,
|
51
|
+
validation_error_messages: ex.error_full_messages.to_a,
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module FailureResult
|
59
|
+
def self.new(exception:, validation_errors:, **kargs)
|
60
|
+
MuchResult.failure(
|
61
|
+
exception: exception,
|
62
|
+
validation_errors: validation_errors,
|
63
|
+
**kargs,
|
27
64
|
)
|
28
65
|
end
|
29
66
|
end
|
data/lib/much-rails/layout.rb
CHANGED
@@ -50,6 +50,14 @@ module MuchRails::Layout
|
|
50
50
|
@javascripts ||= []
|
51
51
|
end
|
52
52
|
|
53
|
+
def head_link(url, **attributes)
|
54
|
+
head_links << HeadLink.new(url, **attributes)
|
55
|
+
end
|
56
|
+
|
57
|
+
def head_links
|
58
|
+
@head_links ||= []
|
59
|
+
end
|
60
|
+
|
53
61
|
def layout(value)
|
54
62
|
layouts << value
|
55
63
|
end
|
@@ -104,12 +112,31 @@ module MuchRails::Layout
|
|
104
112
|
@javascripts ||= self.class.javascripts.map(&:call)
|
105
113
|
end
|
106
114
|
|
107
|
-
def
|
108
|
-
|
115
|
+
def head_links
|
116
|
+
@head_links ||= self.class.head_links
|
109
117
|
end
|
110
118
|
|
111
119
|
def layouts
|
112
120
|
self.class.layouts
|
113
121
|
end
|
122
|
+
|
123
|
+
def any_breadcrumbs?
|
124
|
+
breadcrumbs.any?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class HeadLink
|
129
|
+
attr_reader :href, :attributes
|
130
|
+
|
131
|
+
def initialize(href, **attributes)
|
132
|
+
@href = href
|
133
|
+
@attributes = attributes
|
134
|
+
end
|
135
|
+
|
136
|
+
def ==(other)
|
137
|
+
super unless other.is_a?(self.class)
|
138
|
+
|
139
|
+
href == other.href && attributes == other.attributes
|
140
|
+
end
|
114
141
|
end
|
115
142
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_model/error"
|
3
4
|
require "much-rails/mixin"
|
4
5
|
|
5
6
|
module MuchRails; end
|
@@ -33,7 +34,7 @@ module MuchRails::Records::ValidateDestroy
|
|
33
34
|
|
34
35
|
def destroy!(as: :base, validate: true)
|
35
36
|
if validate && !destroyable?
|
36
|
-
raise DestructionInvalid.new(self, field_name: as)
|
37
|
+
raise MuchRails::Records::DestructionInvalid.new(self, field_name: as)
|
37
38
|
end
|
38
39
|
|
39
40
|
# `_raise_record_not_destroyed` is from ActiveRecord. This logic was
|
@@ -61,22 +62,31 @@ module MuchRails::Records::ValidateDestroy
|
|
61
62
|
raise NotImplementedError
|
62
63
|
end
|
63
64
|
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class MuchRails::Records::DestructionInvalid < StandardError
|
68
|
+
attr_reader :record, :errors, :error_full_messages
|
64
69
|
|
65
|
-
|
66
|
-
|
70
|
+
def initialize(record = nil, field_name: :base)
|
71
|
+
super(record&.destruction_error_messages.to_a.join("\n"))
|
67
72
|
|
68
|
-
|
69
|
-
super(record&.destruction_error_messages.to_a.join("\n"))
|
73
|
+
@record = record
|
70
74
|
|
71
|
-
|
75
|
+
messages = record&.destruction_error_messages.to_a
|
76
|
+
@errors =
|
77
|
+
if messages.any?
|
78
|
+
{ field_name.to_sym => messages }
|
79
|
+
else
|
80
|
+
{}
|
81
|
+
end
|
72
82
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
83
|
+
@error_full_messages =
|
84
|
+
if field_name == :base
|
85
|
+
messages
|
86
|
+
else
|
87
|
+
messages.map do |m|
|
88
|
+
ActiveModel::Error.new(@record, field_name, m).full_message
|
79
89
|
end
|
80
|
-
|
90
|
+
end
|
81
91
|
end
|
82
92
|
end
|
@@ -4,6 +4,7 @@ require "active_record"
|
|
4
4
|
require "much-rails/mixin"
|
5
5
|
require "much-rails/result"
|
6
6
|
require "much-rails/service"
|
7
|
+
require "much-rails/service_validation_errors"
|
7
8
|
|
8
9
|
module MuchRails; end
|
9
10
|
|
@@ -17,14 +18,50 @@ module MuchRails::SaveService
|
|
17
18
|
|
18
19
|
around_call do |receiver|
|
19
20
|
receiver.call
|
20
|
-
rescue
|
21
|
+
rescue *MuchRails::SaveService::ValidationErrors.exception_classes => ex
|
21
22
|
set_the_return_value_for_the_call_method(
|
22
|
-
MuchRails::
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
MuchRails::SaveService::ValidationErrors.result_for(ex),
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ValidationErrors
|
29
|
+
def self.add(exception_class, &block)
|
30
|
+
service_validation_errors.add(exception_class, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.exception_classes
|
34
|
+
service_validation_errors.exception_classes
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.result_for(ex)
|
38
|
+
service_validation_errors.result_for(ex)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.service_validation_errors
|
42
|
+
@service_validation_errors ||=
|
43
|
+
MuchRails::ServiceValidationErrors
|
44
|
+
.new
|
45
|
+
.tap do |e|
|
46
|
+
e.add(ActiveRecord::RecordInvalid) do |ex|
|
47
|
+
MuchRails::SaveService::FailureResult.new(
|
48
|
+
record: ex.record,
|
49
|
+
exception: ex,
|
50
|
+
validation_errors: ex.record&.errors.to_h,
|
51
|
+
validation_error_messages:
|
52
|
+
ex.record&.errors&.full_messages.to_a,
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module FailureResult
|
60
|
+
def self.new(exception:, validation_errors:, **kargs)
|
61
|
+
MuchResult.failure(
|
62
|
+
exception: exception,
|
63
|
+
validation_errors: validation_errors,
|
64
|
+
**kargs,
|
28
65
|
)
|
29
66
|
end
|
30
67
|
end
|