Using cancan to prevent access to controller
Asked Answered
F

5

12

I have an admin controller and I want that only users that are defined as admin would have access to that controller.

my ability class:

class Ability
  include CanCan::Ability

  def initialize(user)
    if user.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end
end

my admin controller:

class AdminController < ApplicationController
  load_and_authorize_resource

  def index
  end

  def users_list
  end
end

when i try to access /admin/users_list (either with an admin user or without) i get the following error: uninitialized constant Admin

What am I doing wrong? Is that the right way to restrict access to a controller?

Fisticuffs answered 25/12, 2010 at 12:1 Comment(0)
S
31

This is because when you are using load_and_authorize_resource your controller must be backed by a model named Admin (since your controller is called AdminController). Thus you need to either create this model or replace load_and_authorize_resource with:

authorize_resource :class => false

which causes the access checks to be made against your actions rather than the model. Note this unfortunately causes the generic access symbols such as :manage and :read to stop working requiring you to refernce the controller actions directly in ability.rb:

can [ :index, :users_list ], :admin

where the first argument is a array of controller actions the user can access and the second argument is the short name of the controller

Spieler answered 31/12, 2010 at 20:40 Comment(1)
Hi, what if I want to split faked resource by types. For example, I have many reports in my projects, but no models for them. Different views goes to the same action build in reports_controller.rb with specific report name. I'm trying to define abilities like this: can :read, :reports, name: ['Orders', 'Payments'] and then check permissions: if can? :read, :reports, name: 'Orders' but error undefined method 'name' for :reports:Symbol is happened. Do you have any ideas?Creamer
J
7

You can put authorization in your controller

authorize_resource :class => false

or

authorize_resource :class => :controller

Then change your app/models/Ability.rb file

can :manage, :controller_name

See this

Judaize answered 31/12, 2012 at 6:15 Comment(0)
E
3

Check this to add authorization rules for non-restful-controllers:

https://github.com/ryanb/cancan/wiki/Non-RESTful-Controllers

Hope this helps.

Ectogenous answered 30/12, 2010 at 6:34 Comment(0)
L
1

This is because when you make a generic controller, put load_and_authorize_resource then the application controller or admin controller could not find the actual class which it come from like this example. This will work.

class Admin::HomeController < Admin::ApplicationController
    def home    
    end
  end

  class Admin::ApplicationController < ApplicationController
    load_and_authorize_resource :class => self.class
  end
Lovelorn answered 23/12, 2011 at 13:36 Comment(0)
E
0

I had the same issue. My solution was define a cannot ability. Insted of define what only the Admin can do, I'm defining what the no admin user can not do. In your code would be something like this:

Admin controller:

class AdminController < ApplicationController
 authorize_resource :class => AdminController

 def index
 end

 def users_list
 end
end

ability.rb:

class Ability
 include CanCan::Ability

 def initialize(user)
  if user.admin?
   can :manage, :all
  else
   can :read, :all
   cannot [:index, :users_list], AdminController
  end
 end
end
Evolve answered 18/2, 2015 at 12:1 Comment(1)
I just learned about the possibility to define methods like: can [:show], SettingsController if user.admin? so nifty, thanks!Tindle

© 2022 - 2024 — McMap. All rights reserved.