Search code examples
ruby-on-railsrubyerror-handlingcancancancancan

Rails: CanCanCan - AccessDenied error not displaying


I'm using CanCanCan in my rails app for authorization. The routes and redirects work fine but I don't manage to display the AccessDenied error message (it worked before but I must have messed something up on the way and now it just won't show).

Here's my code:

controllers/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, error: exception.message
  end
  ...
end

(I changed the default :alert to :error as otherwise I was ending up with an alert from devise ('You are already logged in').

views/index.html.haml (root)

= flash[:error] if flash[:error]
...

Any ideas on how to get it to work again? Thanks in advance.

---EDIT---

Some more fixes I tried (without success):

  • Replacing error with message and notice

  • Removing the rescue_from CanCan::AccessDenied method completely - it brought me to the standard CanCan error page (so I know the method itself is working).

  • Replacing the exception.message with a regular string.

  • Adding a puts statement before redirection - it gets printed in the console as one would expect.

  • As @Anand Shah suggest in an answer to this question, I added the following in my view:

- if flash[:error].blank?
%p flash hash is blank

The hash was indeed empty, so it seems like the flash is not being saved at all. Then I added

flash.keep(:error)

in my controller but that didn't change anything.


Solution

  • The reason for this issue turned out to be my routes.rb. In addition to defining the root for devise scope:

    devise_scope :user do
      root to: "devise/sessions#new"
    end
    
    authenticated :user do
      root 'application#show', as: :authenticated_root
    end
    

    I also had an extra root defined (which basically caused double redirection and therefore loss of the alert):

    root to: 'application#show'
    

    The code from the documentation works just fine after the necessary modification (note I could bring it back from error to alert without breaking things):

    rescue_from CanCan::AccessDenied do |exception|
      redirect_to root_url, alert: exception.message
    end