1

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!

0

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I suggest an emphasis on the fact that the validations you are talking about are Rails validations
Thank You, that was exactly what was going on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.