In my Rails 3.2 app, I'm trying to use config.exceptions_app to route exceptions through the routing table to render error-specific pages (especially one for 401 Forbidden). Here's what I've got so far for configuration:
# application.rb
config.action_dispatch.rescue_responses.merge!('Error::Forbidden' => :forbidden)
config.exceptions_app = ->(env) { ErrorsController.action(:show).call(env) }
# development.rb
config.consider_all_requests_local = false
# test.rb
config.consider_all_requests_local = false
And now the meat of the matter:
module Error
class Forbidden < StandardError
end
end
class ErrorsController < ApplicationController
layout 'error'
def show
exception = env['action_dispatch.exception']
status_code = ActionDispatch::ExceptionWrapper.new(env, exception).status_code
rescue_response = ActionDispatch::ExceptionWrapper.rescue_responses[exception.class.name]
render :action => rescue_response, :status => status_code, :formats => [:html]
end
def forbidden
render :status => :forbidden, :formats => [:html]
end
end
When I want to render that 401 response, I simply raise Error::Forbidden
which, in the development environment works perfectly. But when running an example in rspec, e.g.:
it 'should return http forbidden' do
put :update, :id => 12342343343
response.should be_forbidden
end
it fails miserably:
1) UsersController PUT update when attempting to edit another record should return http forbidden
Failure/Error: put :update, :id => 12342343343
Error::Forbidden:
Error::Forbidden
Could someone help me understand why this doesn't work in my test environment? I could put a #rescue_from in ApplicationController, but if I have to do that to get my tests working, I'm not sure what the point of using config.exceptions_app
is in the first place. :-\
EDIT: As a workaround, I wound up putting the following at the end of config/environments/test.rb It's hecka gross, but seems to work okay.
module Error
def self.included(base)
_not_found = -> do
render :status => :not_found, :text => 'not found'
end
_forbidden = -> do
render :status => :forbidden, :text => 'forbidden'
end
base.class_eval do
rescue_from 'ActiveRecord::RecordNotFound', :with => _not_found
rescue_from 'ActionController::UnknownController', :with => _not_found
rescue_from 'AbstractController::ActionNotFound', :with => _not_found
rescue_from 'ActionController::RoutingError', :with => _not_found
rescue_from 'Error::Forbidden', :with => _forbidden
end
end
end
In
config/environments/test.rb
set:I had the same issue. Be careful where you raise your exception. If it is in a
before_filter
/before_action
, your exception will be swallowed. Move your finder code to the actual method and your exception should show up in your specs.