Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #10688 (reopened enhancement)

Opened 4 months ago

Last modified 6 days ago

assert_response should give the exception message when 500 occurs

Reported by: loincloth Assigned to: core
Priority: normal Milestone: 2.1
Component: ActionPack Version: edge
Severity: normal Keywords:
Cc: cch1

Description

I frequently found myself wanting to know this information for unexpected 500s. It seems like the current assert_response message on failure is OK for other responses because you likely have code which triggers different responses within your request body which would make debugging a clear path. In the case of a 500, it could be just about anything that blew up, so it would be real nice to know what exactly without having to guess or open the browser to see the error page.

In some cases opening the browser wouldn't even help, it seems. For example, when a Mocha expectation was not met, I found it being set as the template exception rather than surfaced as a failure as it usually is. Perhaps this points to a different problem altogether, I'm not sure.. at any rate, I find this hack useful.

On a perhaps less important note regarding my implementation, I find it a little odd that the template instance doesn't surface an accessor for its @exception. Quick searches for 'exception' in ActionView::Base and TestProcess didn't yield anything, so I'm calling this good enough. But, perhaps a detail to consider. I only found how the message was stored by doing :inspect on the whole response object and wading through the output.

Attachments

assert_response_with_exception_message_for_500.diff (3.3 kB) - added by loincloth on 01/04/08 04:30:36.

Change History

01/04/08 01:26:19 changed by bitsweat

  • milestone changed from 2.x to 2.1.

Nice patch. Needs a unit test.

01/04/08 04:30:36 changed by loincloth

  • attachment assert_response_with_exception_message_for_500.diff added.

01/04/08 04:31:30 changed by loincloth

Patch updated. Added basic coverage for assert_response with all status codes defined in ActionController::StatusCodes as well.

01/05/08 02:19:52 changed by bitsweat

  • status changed from new to closed.
  • resolution set to fixed.

(In [8559]) assert_response failures include the exception message. Closes #10688.

05/07/08 13:55:56 changed by cch1

  • cc set to cch1.
  • status changed from closed to reopened.
  • resolution deleted.

Nice idea... but...

This code introduces a dependency on the @exception instance variable. In cases of managed exceptions, it does not normally exist. For example, if I have:

def rescue_action_in_public(exception)

@message = exception.message

@status = response_code_for_rescue(exception) # ActionController::StatusCodes

@redirect = request.envHTTP_REFERER? home_path respond_to do |format|

format.html { flash[:error] = "#{@message} (#{interpret_status(@status)})"; redirect_to @redirect } format.js { render :template => 'shared/alert', :status => @status, :layout => false } format.xml { x = Builder::XmlMarkup.new;x.instruct!;x.error(@message); render :xml => x.target!, :status => @status } format.json { render :json => @message.to_json, :status => @status } format.all { render :text => @message, :status => @status }

end

end

With this type of error management, Integration testing now raises its own exception when @exception is not defined. Ugly...

Need to make this code more robust.

05/07/08 13:59:31 changed by cch1

Once again, with proper formatting and a stack trace:

def rescue_action_in_public(exception)
      @exception = exception
      @message ||= exception.message
      @status ||= response_code_for_rescue(exception)  # ActionController::StatusCodes
      @redirect ||= request.env["HTTP_REFERER"] || home_path
      respond_to do |format|
        format.html { flash[:error] = "#{@message} (#{interpret_status(@status)})"; redirect_to @redirect }
        format.js { render :template => 'shared/alert', :status => @status, :layout => false }
        format.xml { x = Builder::XmlMarkup.new;x.instruct!;x.error(@message); render :xml => x.target!, :status => @status }
        format.json { render :json => @message.to_json, :status => @status }
        format.all { render :text => @message, :status => @status }
      end
end

The error I see is:

Exception: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.message
/Users/cch1/Documents/Development/mmweb/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb:37:in `assert_response'
/Users/cch1/Documents/Development/mmweb/vendor/rails/actionpack/lib/action_controller/assertions.rb:54:in `clean_backtrace'
/Users/cch1/Documents/Development/mmweb/vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb:28:in `assert_response'
./test/integration/web_service_test.rb:347:in `ws_create_medium'
...