Reputation: 13
I am attempting to test returning errors on a non-unique attempt at creating a user in this API.
RSpec.describe 'POST /signup', type: :request do
let(:url) { '/signup' }
let(:params) do
{
user: {
email: '[email protected]',
password: 'password'
}
}
end
context 'when user is unauthenticated' do
before { post url, params: params }
it 'returns 200' do
expect(response.status).to eq 200
end
it 'returns a new user' do
expect(response).to match_response_schema('user')
end
end
context 'when user already exists' do
before do
Fabricate :user, email: params[:user][:email]
post url, params: params
end
it 'returns bad request status' do
expect(response.status).to eq 400
end
it 'returns validation errors' do
expect(json['errors'].first['title']).to eq('Bad Request')
end
end
end
Above is my spec file. Below is the registration file that is throwing the error:
class RegistrationsController < Devise::RegistrationsController
respond_to :json
def create
build_resource(sign_up_params)
resource.save
render_resource(resource)
end
end
The error that I am getting:
3) POST /signup when user already exists returns validation errors
Failure/Error: resource.save
ActiveRecord::RecordNotUnique:
SQLite3::ConstraintException: UNIQUE constraint failed: users.email:
INSERT INTO "users" ("email", "encrypted_password") VALUES (?, ?)
I know that it is going to throw that error, that's the point I've defined the following in my application controller to return the correctly formatted error:
class ApplicationController < ActionController::API
def render_resource(resource)
if resource.errors.empty?
render json: resource
else
validation_error(resource)
end
end
def validation_error(resource)
render json: {
errors: [
{
status: '400',
title: 'Bad Request',
detail: resource.errors,
code: '100'
}
]
}, status: :bad_request
end
end
The goal is that if resource.save
doesn't save, or throws and error that the render_resource
function will return a JSON formatted error. However, every time it hits the resource.save
it throws the error in my test and stops the rest of the test. Any help would be greatly appreciated!
Upvotes: 1
Views: 721
Reputation: 106792
save
returns false
and populates errors
when a record wasn't saved to the database because of failing validations. In your case, there aren't failing any validations but the database raised an exception. These kinds of errors aren't handled in your code.
A unique index in the database is important to really ensure that you do not end up with duplicates in your database, but you still should add a validation to your model to show nice error messages to the user.
# add to app/models/user.rb
validates :email, uniqueness: { case_sensitive: false }
Read more about this type of validation in the Rails Guides.
Upvotes: 1