Search code examples
ruby-on-railsrubyruby-on-rails-4devisecancan

Not Authorized when using CanCan and Devise (Rails 4)


I am trying to serve up some resources on a custom route, but an being denied access via my CanCan gem.

PlaysController with custom route: upcoming_plays

class PlaysController < ApplicationController
  load_and_authorize_resource

  def upcoming_plays
    @plays = Play.where("date_of_play >= ?",Time.now ).order(date_of_play: :desc )
  end
  #...
end

app/views/plays/upcoming_plays.html.erb

<!-- This displays links to plays/ID for play occurring in the future-->
<div id="show-all-plays"> 
  <% @plays.each do |current_play| %>
      <%= render partial: "layouts/play_link" , 
          locals: {play: current_play} %>
  <% end %>
</div>

config/routes.rb

Rails.application.routes.draw do
  get 'plays/upcoming_plays', :as => 'upcoming_plays', :path=>'upcoming_plays'
  #...
end

app/models/ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    if user != nil and user.role == 'admin'
       can :manage, :all
     else
       can :read, :all
     end
  end
end

Received error on navigation to /upcoming_plays.html :

You are not authorized to access this page.

and it blocks me from viewing that page with a redirect to root page

I am not sure if CanCan believes I am attempting to manage/modify the Plays Model, but all I am trying to do is read the values from the DB. Any ideas? Thank you for the help!

Edit: Rokibul Hasan suggested adding

skip_authorize_resource :only => :upcoming_plays

to the plays controller. Which worked! However this seems like a hack. What if I want to add the ability for an admin to edit things on this page? I don't want the the forbidden actions to be available to everyone. Seems like this could be an issue, any ideas?


Solution

  • Seems problem is in your ability class, Can you please rewrite you ability as following

    class Ability
     include CanCan::Ability
    
      def initialize(user)
         user ||= User.new  
         if user.role == 'admin'
           can :manage, :all
         else
           can :read, :all
         end
      end
    end
    

    load_and_authorize_resource can authorize automatically for every action in your controller. For an alternate solution you can add following code to your controller to skip upcoming_plays from authorize.

     skip_authorize_resource :only => :upcoming_plays