0

I'm writing a test to check for invalid DELETE requests to a Rails API using Rspec.

This is what I have:

context 'invalid id number' do
  it 'returns success: false' do
      xhr :delete, :destroy, id: 999999999999999999
      expect(JSON.parse(response.body)['success']).to be_false
  end
end

Postgres throws some kind of integer overflow exception (as it should), but in my spec I can't look at the JSON object because it's never formed. How can I make it return { success : false } instead of a blank string? How do I force the JSON object to return despite the exception?

When I use pry to look at the json object, I get this error: JSON::ParserError: A JSON text must at least contain two octets! because response.body evaluates to the empty string ""

Whoa, almost forgot to include the controller code.

def destroy
  if (site == ::MyModel.find(params[:id]))
    site.destroy
    render :json => {success: true}
  else
    render :json => {success: false} 
end
Ben Poon
  • 125
  • 10

2 Answers2

1

By the sounds of it you will need some kind of rescue statement for the exception:

rescue ArithmeticException => ex
  # We need to complete the contract and return json here
  @response = { success: false }
end 

If you want to learn more about contracts check out this link

Remember to stay away from returning objects in failure responses, as if you send back something like site in this case and site does not exist or the database connection is not there your exception response code may have its own exception!

Also try and stay away from rescue Exception => e explanation here: Why is it a bad style to `rescue Exception => e` in Ruby?

TLDR: Your request always expects a json response so in all places even failure it should return one.

Community
  • 1
  • 1
Jesse Whitham
  • 824
  • 9
  • 32
1

There are two issues here:

  1. Depending on your database an id of "999999999999999999" is probably outside of an integer type. I recommend reducing it to below signed integer limit, like 9999.

  2. You are trying to find a non-existent record and its raising a record_not_found exception. I recommend changing your destroy method to:


def destroy
  site = ::MyModel.find_by(id:params[:id])
  if (site.present?)
    render :json => {success: false} 
  else
    site.first.destroy
    render :json => {success: true}
  end
end

EDIT

@rafb3 is correct find_by and present? is a better choice.

eabraham
  • 4,094
  • 1
  • 23
  • 29
  • you can save a query by using `find_by(id: ...)` and then checking `site.present?`. This way you avoid running the query for `empty?` – rafb3 Dec 17 '14 at 14:57