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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bf08e9a5f11a8a2597b17d7aa796d5e749fba3197e9d342b45e230d818d7fc8
4
- data.tar.gz: 794522b0a10b417994189c85599f9fbd4106c1ad002b4b04d3bfe8a788bd4951
3
+ metadata.gz: d5a9113cb9c28d12b0bcffbf5df47f43c2efe956dcb3eae246643461029af788
4
+ data.tar.gz: 95d5050085a06b6b747217b61d04197972948de584f48125bad8c858896913dc
5
5
  SHA512:
6
- metadata.gz: b53df073f7f24299b154a06d16dc94ef01fce26e719065201efa523d683f52c5a65a8c2570a3542ae595e43d91a94a6d4df2d486d6fba5141d3120e9ac6e244e
7
- data.tar.gz: 381f52f7be00bba2d90da5904a998d450d6077461e7f6d85fffd49fd749512d073759e9827db4f6db0ae2eaf38c1dc78044a35b69fe4a80ee550472c380fa905
6
+ metadata.gz: 9699a1c4fede48c47b4e7e47148a3dc256b0d3ee29d8b681041614719b9d734946fc001599704f26237637bacaf204013ed01b5c8ff72d3cbceeb049bb5ea407
7
+ data.tar.gz: c550915e3af0b1142e73ad28b60e2e6944f5d789e769bbc31dcd35f07ace0ed16ba1bb18f253b8392b53b363167da70b33539589448d73bc1e21992341748768
@@ -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
- Definition
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
- .tap{ |definition| @definitions << definition }
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
- path: url.path,
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, :path, :name, :default_params
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
- path:,
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
- @path = path
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
- @path == other.path &&
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 :require_much_rails_action_class
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(MuchRails::Action::Router::CONTROLLER_METHOD_NAME) do
27
+ define_method(
28
+ MuchRails::Action::Router::CONTROLLER_CALL_ACTION_METHOD_NAME,
29
+ ) do
23
30
  respond_to do |format|
24
- format.public_send(much_rails_action_class.format) do
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
- CONTROLLER_METHOD_NAME = :much_rails_call_action
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
- draw_route_to = "#{controller_name}##{CONTROLLER_METHOD_NAME}"
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::Records::ValidateDestroy::DestructionInvalid => ex
21
+ rescue *MuchRails::DestroyService::ValidationErrors.exception_classes => ex
22
22
  set_the_return_value_for_the_call_method(
23
- MuchRails::Result.failure(
24
- exception: ex,
25
- validation_errors: ex&.destruction_errors.to_h,
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
@@ -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 any_breadcrumbs?
108
- breadcrumbs.any?
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
- class DestructionInvalid < StandardError
66
- attr_reader :record, :destruction_errors
70
+ def initialize(record = nil, field_name: :base)
71
+ super(record&.destruction_error_messages.to_a.join("\n"))
67
72
 
68
- def initialize(record = nil, field_name: :base)
69
- super(record&.destruction_error_messages.to_a.join("\n"))
73
+ @record = record
70
74
 
71
- @record = record
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
- messages = record&.destruction_error_messages.to_a
74
- @destruction_errors =
75
- if messages.any?
76
- { field_name.to_sym => messages }
77
- else
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
- end
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 ActiveRecord::RecordInvalid => ex
21
+ rescue *MuchRails::SaveService::ValidationErrors.exception_classes => ex
21
22
  set_the_return_value_for_the_call_method(
22
- MuchRails::Result.failure(
23
- record: ex.record,
24
- exception: ex,
25
- validation_errors: ex.record&.errors.to_h,
26
- validation_error_messages: ex.record&.errors&.full_messages.to_a,
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