Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Double render error when rescuing from CanCan::AccessDenied #620

Closed
pduersteler opened this Issue · 4 comments

2 participants

@pduersteler

Not quite sure if this is really an issue, but I feel like posting it here.

I am trying to rescue from CanCan::AccessDenied like I rescue from e.g. ActiveRecord::RecordNotFound and several other exceptions. It works except for CanCan, where I get an AbstractController::DoubleRenderError.

class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordNotFound, :with => lambda { |e| exception_layout(e, 404) }
  rescue_from CanCan::AccessDenied, :with => lambda { |e| exception_layout(e, 401) }

  private

  def exception_layout(e, errcode = 404)
    render :layout => false, :file => 'layouts/rescue', :locals => {:e => e, :errcode => errcode} and return
  end
end

How can I resolve this problem? I also asked on StackOverflow, but without success by now. (See http://stackoverflow.com/questions/10581761/doublerendererror-by-cancan)

@derekprior
Collaborator

What does the controller that generates this DoubleRenderError look like? Is it possible you have one line that's generating, say a 404 preceding a line that calls authorize? Or perhaps you are trying to authorize two resources that you don't have access to?

There's no code in your rescue code that stops the execution of further lines. If you got one auth failure it would be rescued and then a second auth failure would also be rescued, causing 2 calls to :render.

@pduersteler

I loaded the resource manually and then checked authorization within an after_filter. This obviously is wrong because it authorizes after the action which is nonsense. Changing it to a before_filter fixed it.

I am still curious, there is no other exception that could get raised/rescued before cancan's which would explain the double render error. The problem occured when requesting the index action without propriate permissions.

class RolesController < ApplicationController
  before_filter :find_role, :only => [:show, :edit, :update, :destroy]
  before_filter :authorize # this was an after_filter which was wrong. 

  private

  def find_role
    @role = current_scope.roles.find(params[:id])
  end

  def authorize
    authorize! self.action_name.to_sym, current_scope.roles.new
  end
end

However, I am happy that it works now, thanks to your input! And maybe someone stumbles upon this and thinks it's helpful.

@derekprior
Collaborator

The action's call to render had happened and then your after filter kicked in. It raised an exception which had another call to render. That's why it didn't work.

@pduersteler

Oh god, of course. Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.