rss resume / curriculum vitae linkedin linkedin gitlab github twitter mastodon instagram
Today I learned: Bypass rescue
Mar 29, 2017

One of my job goals this sprint is to implement a new controller that internally uses our proprietary ACL and it is available only for what we call the Super Admin Role. Obviously this new code will have to be backed up by its own specs where we will be covering the two possible cases:

  1. When a valid user has enough permissions (super admin) to access the action, and
  2. When a valid user does not have enough permissions to access the action.

Depending on what you use for authentication you will do different things to log in your user, but what is important is the actual section in the spec that tests both cases defined above.

The easiest one to implement is obviously the case where the user is super admin, assuming we were testing the show method in the controller it would look something like this:

describe 'GET show' do
  let(:user) { create(:user, :super_admin) }

  it 'has access' do
    get :show
    expect(response).to have_http_status(:success)
end # GET show

Our internal ACL works similar to cancancan where a rescue_from is added to the main ApplicationController to render the Access Denied page. Think of the following snippet:

rescue_from AccessDenied do
  respond_to do |format|
    format.html { render 'access_denied' }
    format.js   { render 'access_denied' }

The funny thing is that if you only replace the user with one with less permissions and practically copy/paste the spec from above your new test will still pass because although the user has no access, the final response still succeeds.

Enter bypass_rescue, now if you rewrite your spec for testing your user permissions like this:

describe 'GET show' do
  before { bypass_rescue }

  let(:user) { create(:user, :guest) }

  it 'has NO access' do
    expect { get :show }.to raise_error(AccessDenied)
end # GET show

That will really confirm your user has no access to the specific action in your controller.

Back to posts