much-rails 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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