[rspec-users] Specs for controllers and rescue_from

Phillip Koebbe phillipkoebbe at gmail.com
Sun Nov 21 06:40:21 EST 2010

I had a similar problem in the past (with RSpec 1.x). I tend to create 
what I call a BaseController in each namespace specifically for shared 
behavior. The best example of this is

class Admin::BaseController < ApplicationController
     before_filter :require_logged_in
     before_filter :require_admin


     def require_admin
         redirect_to error_path(403) unless current_user.is_administrator

[:require_logged_in is defined in ApplicationController because it is 
also used by User::BaseController.]

More comments inline.

On 2010-11-20 10:12 PM, Nick Hoffman wrote:
> Hey guys. My ApplicationController rescues
> Mongoid::Errors::DocumentNotFound errors like this:
> class ApplicationController<  ActionController::Base
>    rescue_from Mongoid::Errors::DocumentNotFound,
>      :with =>  :resource_not_found
>    protected
>    def resource_not_found(error)
>      flash[:alert] = t('errors.resource_not_found')
>      redirect_to root_url
>    end
> end
> Obviously, I need specs for this. However, I can't figure out how this
> should be specced.
> Should I create a shared example group that expects the flash-alert
> and redirect, and use it in every controller action that could
> potentially raise this error? This seems right, but will be verbose.

I started to go this route as it seemed most appropriate to spec a 
controller's behavior in that controller, but since the behavior was 
going to be the same in all such controllers, a shared example made 
perfect sense. I was happily specing against the index action of such 
controllers, until I came to one that didn't have an index action. 
Instead of putting in one just to be able to test, I tried figuring out 
how to use an arbitrary action in the shared example. But that became 
too complicated very quickly. There very well might be a way to do this, 
but I was unable to get to it.

> Or, in each controller that could raise this error, should I create
> one example group that raises this error and expects the flash-alert
> and redirect? This seems right because the rescuing behaviour exists
> within the controller rather than each action. However, it ignores the
> possibility of an action rescuing the error.

Could you not also spec it in actions that you see as possible sources 
of the exception? This approach would certainly be most verbose, but 
maybe you should start here and see what pattern develops that could 
lead you down the proper path of refactoring.

> Should I create a dummy controller with an action that raises this
> error, and spec that? This would be akin to speccing
> ApplicationController, though indirectly. This method was my first
> inclination, but fails to provide specs for the other controllers that
> inherit the rescuing behaviour.

Ultimately, I went this direction. I more or less applied the logic that 
I would with a plugin: if the plugin is well tested and I trust it, do I 
really need to test it wherever it is used? Here is what I ended up with:

require 'controller_helper'

describe Admin::BaseController do
     should_descend_from ApplicationController
     should_have_before_filter :require_logged_in
     should_have_before_filter :require_admin

class Admin::BogusController < Admin::BaseController
     def index
         render :nothing => true

ActionController::Routing::Routes.draw do |map|
     map.namespace :admin do |admin|
         admin.resources :bogus

describe Admin::BogusController do
     context 'when the user is not logged in' do
         before(:each) { get :index }

         it 'should redirect to login path' do
             response.should redirect_to(login_path)

     context 'when accessed by administrative users' do
         before :each do
             get :index

         it 'should not redirect to error path 403' do
             response.should_not redirect_to(error_path(403))


     context 'when accessed by non-administrative users' do
         before :each do
             get :index

         it 'should redirect to error path 403' do
             response.should redirect_to(error_path(403))

I'm not sure if this is what I'd do today, but this did solve my problem 
before. My preference would have been the shared examples, but I don't 
want my tests to be too complicated.


More information about the rspec-users mailing list