Skip to content

Commit 0e13ab6

Browse files
committed
Refactor JSONAPI::Rails::ActiveModelError.
1 parent a7e6841 commit 0e13ab6

File tree

3 files changed

+60
-37
lines changed

3 files changed

+60
-37
lines changed

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
source 'https://rubygems.org'
22

3+
# TODO(beauby): Remove before merging.
4+
gem 'jsonapi-serializable', github: 'jsonapi-rb/jsonapi-serializable', branch: 'refactor-errors-renderer'
5+
36
gemspec

lib/jsonapi/rails/active_model_errors.rb

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,32 @@
11
module JSONAPI
22
module Rails
3-
class ActiveModelError
4-
def initialize(field, message, source)
5-
@field = field
6-
@message = message
7-
@source = source
3+
class ActiveModelError < Serializable::Error
4+
title do
5+
"Invalid #{@field}" unless @field.nil?
6+
end
87

9-
freeze
8+
detail do
9+
@message
1010
end
1111

12-
def as_jsonapi
13-
{}.tap do |hash|
14-
hash[:detail] = @message
15-
hash[:title] = "Invalid #{@field}" unless @field.nil?
16-
hash[:source] = { pointer: @source } unless @source.nil?
17-
end
12+
source do
13+
pointer @pointer unless @pointer.nil?
1814
end
1915
end
2016

2117
class ActiveModelErrors
22-
def initialize(errors, reverse_mapping)
23-
@errors = errors
24-
@reverse_mapping = reverse_mapping || {}
18+
def initialize(exposures)
19+
@errors = exposures[:object]
20+
@reverse_mapping = exposures[:_jsonapi_pointers] || {}
2521

2622
freeze
2723
end
2824

2925
def to_a
3026
@errors.keys.flat_map do |key|
3127
@errors.full_messages_for(key).map do |message|
32-
ActiveModelError.new(key, message, @reverse_mapping[key])
28+
ActiveModelError.new(field: key, message: message,
29+
pointer: @reverse_mapping[key])
3330
end
3431
end
3532
end

lib/jsonapi/rails/renderer.rb

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,75 @@
44
module JSONAPI
55
module Rails
66
class SuccessRenderer
7-
def initialize(renderer = JSONAPI::Serializable::SuccessRenderer.new)
7+
def initialize(renderer = JSONAPI::Serializable::Renderer.new)
88
@renderer = renderer
99

1010
freeze
1111
end
1212

1313
def render(resources, options, controller)
14-
options = options.dup
15-
16-
if (pagination_links = controller.jsonapi_pagination(resources))
17-
(options[:links] ||= {}).merge!(pagination_links)
18-
end
19-
options[:expose] =
20-
controller.jsonapi_expose.merge!(options[:expose] || {})
21-
options[:jsonapi] =
22-
options[:jsonapi_object] || controller.jsonapi_object
14+
options = default_options(options, controller, resources)
2315

2416
@renderer.render(resources, options)
2517
end
18+
19+
private
20+
21+
# @api private
22+
def default_options(options, controller, resources)
23+
options.dup.tap do |options|
24+
if (pagination_links = controller.jsonapi_pagination(resources))
25+
(options[:links] ||= {}).merge!(pagination_links)
26+
end
27+
options[:expose] = controller.jsonapi_expose
28+
.merge!(options[:expose] || {})
29+
options[:jsonapi] =
30+
options[:jsonapi_object] || controller.jsonapi_object
31+
end
32+
end
2633
end
2734

2835
class ErrorsRenderer
29-
def initialize(renderer = JSONAPI::Serializable::ErrorsRenderer.new)
36+
def initialize(renderer = JSONAPI::Serializable::Renderer.new)
3037
@renderer = renderer
3138

3239
freeze
3340
end
3441

3542
def render(errors, options, controller)
36-
options = options.merge(_jsonapi_pointers: controller.jsonapi_pointers)
37-
# TODO(beauby): SerializableError inference on AR validation errors.
43+
options = default_options(options, controller)
3844

3945
errors = [errors] unless errors.is_a?(Array)
4046
errors = errors.flat_map do |error|
41-
if error.respond_to?(:as_jsonapi)
42-
error
43-
elsif error.is_a?(ActiveModel::Errors)
44-
ActiveModelErrors.new(error, options[:_jsonapi_pointers]).to_a
45-
elsif error.is_a?(Hash)
46-
JSONAPI::Serializable::Error.create(error)
47+
if error.is_a?(ActiveModel::Errors)
48+
klass = if options[:inferrer] &&
49+
options[:inferrer].key?(:'ActiveModel::Errors')
50+
options[:inferrer][:'ActiveModel::Errors']
51+
else
52+
JSONAPI::Rails::ActiveModelErrors
53+
end
54+
klass = klass.safe_constantize if klass.is_a?(String)
55+
klass.new(options[:expose].merge(object: error)).to_a
4756
else
48-
raise # TODO(lucas): Raise meaningful exception.
57+
error
4958
end
5059
end
5160

52-
@renderer.render(errors, options)
61+
@renderer.render_errors(errors, options)
62+
end
63+
64+
private
65+
66+
# @api private
67+
def default_options(options, controller)
68+
options.dup.tap do |options|
69+
options[:expose] =
70+
controller.jsonapi_expose
71+
.merge!(options[:expose] || {})
72+
.merge!(_jsonapi_pointers: controller.jsonapi_pointers)
73+
options[:jsonapi] =
74+
options[:jsonapi_object] || controller.jsonapi_object
75+
end
5376
end
5477
end
5578
end

0 commit comments

Comments
 (0)