Skip to content

Commit f11622c

Browse files
committed
Add basic support for ActiveModel::Errors.
1 parent 57aa643 commit f11622c

File tree

4 files changed

+43
-7
lines changed

4 files changed

+43
-7
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+
gem 'jsonapi-deserializable', '0.1.1.beta3',
4+
github: 'jsonapi-rb/deserializable', branch: 'reverse-mapping'
5+
36
gemspec

lib/jsonapi/rails/action_controller.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ module ActionController
77
def self.included(base)
88
base.class_eval do
99
extend ClassMethods
10+
prepend InstanceMethods
11+
end
12+
end
13+
14+
module InstanceMethods
15+
def render(opts = {})
16+
if opts.key?(:jsonapi_error)
17+
mapping = params.to_unsafe_h[:_jsonapi_mapping]
18+
opts = opts.merge(_jsonapi_mapping: mapping)
19+
end
20+
super(opts)
1021
end
1122
end
1223

@@ -42,16 +53,23 @@ def call(env)
4253
request = Rack::Request.new(env)
4354
body = request.params.slice(*JSONAPI_KEYS)
4455
parser.parse!(body)
45-
deserialized_hash = @deserializable_class.call(body)
56+
deserialize!(request, body)
57+
58+
@app.call(env)
59+
end
60+
61+
def deserialize!(request, body)
62+
deserialized = @deserializable_class.new(body)
63+
deserialized_hash = deserialized.to_h
64+
mapping = deserialized.mapping
4665
jsonapi = {}
4766
JSONAPI_KEYS.each do |key|
4867
next unless request.params.key?(key)
4968
jsonapi[key.to_sym] = request.delete_param(key)
5069
end
5170
request.update_param(:_jsonapi, jsonapi)
71+
request.update_param(:_jsonapi_mapping, mapping)
5272
request.update_param(@deserializable_key, deserialized_hash)
53-
54-
@app.call(env)
5573
end
5674
end
5775

lib/jsonapi/rails/railtie.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
require 'action_controller'
33
require 'active_support'
44

5-
require 'jsonapi/rails/parser'
6-
require 'jsonapi/rails/renderer'
7-
85
module JSONAPI
96
module Rails
107
class Railtie < ::Rails::Railtie
118
MEDIA_TYPE = 'application/vnd.api+json'.freeze
9+
require 'jsonapi/rails/parser'
1210
PARSER = JSONAPI::Rails.parser
1311

1412
initializer 'jsonapi-rails.action_controller' do
@@ -23,6 +21,7 @@ class Railtie < ::Rails::Railtie
2321
::ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = PARSER
2422
end
2523

24+
require 'jsonapi/rails/renderer'
2625
::ActionController::Renderers.add :jsonapi do |json, options|
2726
unless json.is_a?(String)
2827
json = JSONAPI::Rails::Renderer.render(json, options)

lib/jsonapi/rails/renderer.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,25 @@ def self.render(resources, options)
1818

1919
class ErrorRenderer
2020
def self.render(errors, options)
21-
# TODO(beauby): SerializableError inference on AR validation errors.
21+
if errors.is_a?(ActiveModel::Errors)
22+
errors = build_active_model_errors(errors, options[:_jsonapi_mapping])
23+
end
2224
JSONAPI::Serializable::ErrorRenderer.render(errors, options)
2325
end
26+
27+
def self.build_active_model_errors(errors, mapping)
28+
error_class = Class.new(JSONAPI::Serializable::Error) do
29+
detail { @detail }
30+
source do
31+
path, name = @attribute
32+
pointer "#{path}/#{name}"
33+
end
34+
end
35+
errors.map! do |attr, error|
36+
attr = mapping[attr]
37+
error_class.new(attribute: attr, detail: error)
38+
end
39+
end
2440
end
2541
end
2642
end

0 commit comments

Comments
 (0)