Skip to content

Commit 0acf7fa

Browse files
author
Michael Deutsch
committed
Make JSONAPI::Rails::ActiveModelError inherit from JSONAPI::Serializable::Error, and add tests.
1 parent 498c2b5 commit 0acf7fa

File tree

9 files changed

+81
-42
lines changed

9 files changed

+81
-42
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module JSONAPI
2+
module Rails
3+
class ActiveModelError < JSONAPI::Serializable::Error
4+
def self.from_errors(errors, reverse_mapping)
5+
errors.keys.flat_map do |field|
6+
errors.full_messages_for(field).map do |message|
7+
new(field, message, reverse_mapping[field])
8+
end
9+
end
10+
end
11+
12+
def initialize(field, message, source)
13+
super(field: field, message: message, source: source)
14+
end
15+
16+
title { @field.present? ? "Invalid #{@field}" : 'Invalid record' }
17+
detail { @message }
18+
19+
source do
20+
pointer @source unless @source.nil?
21+
end
22+
end
23+
end
24+
end

lib/jsonapi/rails/active_model_errors.rb

Lines changed: 0 additions & 39 deletions
This file was deleted.

lib/jsonapi/rails/railtie.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'rails/railtie'
22
require 'action_controller'
33
require 'active_support'
4+
require 'active_model'
45

56
require 'jsonapi/rails/parser'
67
require 'jsonapi/rails/renderer'

lib/jsonapi/rails/renderer.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require 'jsonapi/rails/active_model_errors'
1+
require 'jsonapi/rails/active_model_error'
22
require 'jsonapi/serializable/renderer'
33

44
module JSONAPI
@@ -24,7 +24,7 @@ def self.render(errors, options)
2424
if error.respond_to?(:as_jsonapi)
2525
error
2626
elsif error.is_a?(ActiveModel::Errors)
27-
ActiveModelErrors.new(error, options[:_reverse_mapping]).to_a
27+
ActiveModelError.from_errors(error, options[:_reverse_mapping]).to_a
2828
elsif error.is_a?(Hash)
2929
JSONAPI::Serializable::Error.create(error)
3030
else

spec/active_model_error_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require 'spec_helper'
2+
3+
describe JSONAPI::Rails::ActiveModelError do
4+
class Thing
5+
include ActiveModel::Model
6+
attr_accessor :name, :description
7+
validates :name, presence: true
8+
validates :description, presence: true
9+
end
10+
11+
let(:reverse_mapping) { { name: 'data/attributes/name', description: 'data/attributes/description' } }
12+
13+
context 'building from a model' do
14+
it 'converts the model errors' do
15+
invalid_thing = Thing.new
16+
expect(invalid_thing.valid?).to be false
17+
18+
errors = JSONAPI::Rails::ActiveModelError.from_errors(invalid_thing.errors, reverse_mapping)
19+
errors.sort_by! { |e| e.send(:title) }
20+
21+
expect(errors.size).to eq 2
22+
expect(errors[0].send(:title)).to eq 'Invalid description'
23+
expect(errors[0].send(:detail)).to eq "Description can't be blank"
24+
end
25+
end
26+
end

spec/dummy/app/controllers/tweets_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def create
2424
p request.env['jsonapi_deserializable.reverse_mapping']
2525

2626
unless tweet.save
27-
render jsonapi_errors: tweet.errors
27+
render jsonapi_errors: tweet.errors, status: :unprocessable_entity
2828
return
2929
end
3030

spec/dummy/app/models/tweet.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class Tweet < ApplicationRecord
22
belongs_to :parent, optional: true
33
belongs_to :author, class_name: 'User'
4+
5+
validates :content, presence: true
46
end

spec/requests/crud_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,28 @@ def body
9696
expect(response.body).to be_valid_jsonapi
9797
expect(body['data'].first).to eq(second_tweet['data'])
9898
end
99+
100+
it 'renders errors when trying to create an invalid tweet' do
101+
# Post an invalid tweet
102+
params = {
103+
data: {
104+
type: 'tweets',
105+
attributes: {}
106+
}
107+
}
108+
post '/tweets',
109+
params: params,
110+
as: :json,
111+
headers: headers.merge('CONTENT_TYPE' => 'application/vnd.api+json')
112+
expect(response).to have_http_status(422)
113+
expect(response.body).to be_valid_jsonapi
114+
expect(response.body).to match_schema do
115+
required(:errors).each do
116+
required(:title).value(eql?: 'Invalid content')
117+
required(:detail).value(eql?: "Content can't be blank")
118+
required(:source).value(:hash?)
119+
required(:source).value(:empty?)
120+
end
121+
end
122+
end
99123
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'jsonapi/parser'
2+
require 'jsonapi/rails'
23

34
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
45
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.

0 commit comments

Comments
 (0)