Joanna Gaudyn
Joanna Gaudyn

Reputation: 617

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):

- 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.

Upvotes: 1

Views: 1470

Answers (3)

Joanna Gaudyn
Joanna Gaudyn

Reputation: 617

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

Upvotes: 1

engineersmnky
engineersmnky

Reputation: 29318

Have you tried not handling this inline but rather something like:

 rescue_from CanCan::AccessDenied do |exception|
    flash[:error] =  exception.message
    redirect_to root_url
 end

The reason it was working before is Rails understands :alert and :notice as flash messages during the redirect_to otherwise you should use the "general purpose flash bucket" as they call it via flash: {error: 'your message'}

However the Hash passed to redirect_to can also contain the http status code (:status) and url query parameters (anything that is not :alert, :notice, :status, or :flash and it all just seems like too much noise (IMO) to put a flash message in there to save 1 line of explicit code.

Upvotes: 0

RoRFan
RoRFan

Reputation: 424

Have you tried it through a private browser in case the cookies have messed up?

Can you try this format?

redirect_to(root_url, {:flash => { :error => exception.message }})

Upvotes: 0

Related Questions