Skip to content

Commit e7755e4

Browse files
committed
Merge pull request #13 from b2beauty/hotfix/setup-and-check-request
Setup and check request before action executes
2 parents ad6da1c + 2a7fab6 commit e7755e4

File tree

10 files changed

+111
-24
lines changed

10 files changed

+111
-24
lines changed

jsonapi-utils.gemspec

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ Gem::Specification.new do |spec|
2323

2424
spec.add_development_dependency 'bundler', '~> 1.10'
2525
spec.add_development_dependency 'rake', '~> 10.0'
26-
spec.add_development_dependency 'rspec-rails', '~> 3.1'
27-
spec.add_development_dependency 'smart_rspec', '~> 0.1.4'
2826
spec.add_development_dependency 'sqlite3'
29-
spec.add_development_dependency 'factory_girl', '~> 4.5'
30-
spec.add_development_dependency 'jsonapi-resources', '~> 0.7.0'
3127
spec.add_development_dependency 'rails', '~> 4.2'
28+
spec.add_development_dependency 'rspec-rails', '~> 3.1'
29+
spec.add_development_dependency 'factory_girl', '~> 4.5'
30+
spec.add_development_dependency 'smart_rspec', '~> 0.1.4'
3231
end

lib/jsonapi/utils.rb

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,14 @@ module JSONAPI
66
module Utils
77
def self.included(base)
88
if base.respond_to?(:helper_method)
9-
base.helper_method :jsonapi_serialize
9+
base.before_action :setup_request, :check_request
10+
base.helper_method :jsonapi_render, :jsonapi_serialize
1011
end
1112
end
1213

1314
def jsonapi_render(json:, status: nil, options: {})
14-
setup_request
15-
16-
if @request.errors.present?
17-
render_errors(@request.errors)
18-
else
19-
body = jsonapi_serialize(json, options)
20-
render json: body, status: status || @_response_document.status
21-
end
15+
body = jsonapi_serialize(json, options)
16+
render json: body, status: status || @_response_document.status
2217
rescue => e
2318
handle_exceptions(e)
2419
ensure
@@ -28,8 +23,9 @@ def jsonapi_render(json:, status: nil, options: {})
2823
end
2924

3025
def jsonapi_render_errors(exception)
31-
error = jsonapi_format_errors(exception)
32-
render json: { errors: error.errors }, status: error.code
26+
result = jsonapi_format_errors(exception)
27+
errors = result.errors
28+
render json: { errors: errors }, status: errors.first.status
3329
end
3430

3531
def jsonapi_format_errors(exception)
@@ -54,8 +50,6 @@ def jsonapi_render_not_found_with_null
5450
end
5551

5652
def jsonapi_serialize(records, options = {})
57-
setup_request
58-
5953
if records.is_a?(Hash)
6054
hash = records.with_indifferent_access
6155
records = hash_to_active_record(hash[:data], options[:model])
@@ -258,5 +252,9 @@ def setup_request
258252
server_error_callbacks: (self.class.server_error_callbacks || [])
259253
)
260254
end
255+
256+
def check_request
257+
@request.errors.blank? || render_errors(@request.errors)
258+
end
261259
end
262260
end

lib/jsonapi/utils/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module JSONAPI
22
module Utils
3-
VERSION = '0.4.3'
3+
VERSION = '0.4.4'
44
end
55
end

spec/controllers/posts_controller_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
require 'rspec/expectations'
33

44
describe PostsController, type: :controller do
5+
include_context 'JSON API headers'
6+
57
before(:all) { FactoryGirl.create_list(:post, 3) }
68

79
let(:fields) { (PostResource.fetchable_fields - %i(id author)).map(&:to_s) }

spec/controllers/users_controller_spec.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
require 'spec_helper'
22

33
describe UsersController, type: :controller do
4+
include_context 'JSON API headers'
5+
46
before(:all) { FactoryGirl.create_list(:user, 3, :with_posts) }
57

68
let(:fields) { (UserResource.fetchable_fields - %i(id posts)).map(&:to_s) }
79
let(:relationships) { %w(posts) }
10+
let(:attributes) { { first_name: 'Yehuda', last_name: 'Katz' } }
11+
12+
let(:user_params) do
13+
{ data: { type: 'users', attributes: attributes } }
14+
end
815

916
include_examples 'JSON API invalid request', resource: :users
1017

@@ -225,4 +232,42 @@
225232
end
226233
end
227234
end
235+
236+
describe '#create' do
237+
it 'creates a new user' do
238+
expect { post :create, user_params }.to change(User, :count).by(1)
239+
expect(response).to have_http_status :created
240+
expect(response).to have_primary_data('users')
241+
expect(response).to have_data_attributes(fields)
242+
expect(data['attributes']['first_name']).to eq(user_params[:data][:attributes][:first_name])
243+
end
244+
245+
shared_examples_for '400 response' do |hash|
246+
it 'renders a 400 response' do
247+
user_params[:data][:attributes].merge!(hash)
248+
expect { post :create, user_params }.to change(User, :count).by(0)
249+
expect(response).to have_http_status :bad_request
250+
expect(error['title']).to eq('Param not allowed')
251+
expect(error['code']).to eq(105)
252+
end
253+
end
254+
255+
context 'with a not permitted param' do
256+
it_behaves_like '400 response', foo: 'bar'
257+
end
258+
259+
context 'with a param not present in resource\'s attribute list' do
260+
it_behaves_like '400 response', admin: true
261+
end
262+
263+
context 'when validation fails' do
264+
it 'render a 422 response' do
265+
user_params[:data][:attributes].merge!(first_name: nil)
266+
expect { post :create, user_params }.to change(User, :count).by(0)
267+
expect(response).to have_http_status :unprocessable_entity
268+
expect(error['title']).to eq('Can\'t change this User')
269+
expect(error['code']).to eq(125)
270+
end
271+
end
272+
end
228273
end

spec/spec_helper.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,3 @@ class TestApp < Rails::Application
9797
get :index_with_hash, to: 'posts#index_with_hash'
9898
get :show_with_hash, to: 'posts#show_with_hash'
9999
end
100-

spec/support/controllers.rb

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'support/exceptions'
2+
13
class BaseController < JSONAPI::ResourceController
24
include JSONAPI::Utils
35
protect_from_forgery with: :null_session
@@ -38,7 +40,7 @@ def create
3840
jsonapi_render json: new_post, status: :created
3941
end
4042

41-
private
43+
protected
4244

4345
def load_user
4446
@user = User.find(params[:user_id])
@@ -48,13 +50,29 @@ def load_user
4850
class UsersController < BaseController
4951
# GET /users
5052
def index
51-
@users = User.all
52-
jsonapi_render json: @users
53+
users = User.all
54+
jsonapi_render json: users
5355
end
5456

5557
# GET /users/:id
5658
def show
57-
@user = User.find(params[:id])
58-
jsonapi_render json: @user
59+
user = User.find(params[:id])
60+
jsonapi_render json: user
61+
end
62+
63+
# POST /users
64+
def create
65+
user = User.new(user_params)
66+
if user.save
67+
jsonapi_render json: user, status: :created
68+
else
69+
jsonapi_render_errors ::Exceptions::ActiveRecordError.new(user)
70+
end
71+
end
72+
73+
protected
74+
75+
def user_params
76+
params.require(:data).require(:attributes).permit(:first_name, :last_name, :admin)
5977
end
6078
end

spec/support/exceptions.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Exceptions
2+
class ActiveRecordError < ::JSONAPI::Exceptions::Error
3+
attr_accessor :object
4+
5+
def initialize(object)
6+
@object = object
7+
end
8+
9+
def errors
10+
[JSONAPI::Error.new(
11+
code: 125,
12+
status: :unprocessable_entity,
13+
title: "Can't change this #{@object.class.name}",
14+
detail: @object.errors)]
15+
end
16+
end
17+
end

spec/support/models.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
create_table :users, force: true do |t|
1515
t.string :first_name
1616
t.string :last_name
17+
t.boolean :admin
1718
t.timestamps null: false
1819
end
1920
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
shared_context 'JSON API headers' do
2+
let(:headers) do
3+
{ 'Accept' => 'application/vnd.api+json',
4+
'Content-Type' => 'application/vnd.api+json' }
5+
end
6+
7+
before(:each) { request.headers.merge!(headers) }
8+
end

0 commit comments

Comments
 (0)