Search code examples
ruby-on-railscontrollercancan

Cancan ability definition: whole controller as an object


My question is absolutely theoretic, like "Is it right thing to do?". I'm new to Rails in particular and to Ruby in general, and I'm trying to use Cancan autorization solution for my Rails appilcation.

Let's consider we have a simple contoller like this, a pair of associated views and an User model with DB table.

class UsersController < ApplicationController
  def index
    @users = User.all
  end
  def show
    @user = User.find(params[:id])
  end
end

The goal is to restrict access to the "index" method to all but admins and permit regular users to see only their own pages, e.g. to permit user with id==5 to see page "users/5". For this scope I've create an ability class for Cancan. Here it is:

class Ability
  include CanCan::Ability

  def initialize user, options = {}
    default_rules
    if user
      admin_rules(user) if user.role.eql? "admin"
      player_rules(user) if user.role.eql? "player"
    end
  end

  def admin_rules user
    can :read, UsersController
  end

  def player_rules user
    can :read, User do |user_requested|
      user_requested.id == user.id
    end 
  end

  def default_rules 
  end
end

My question is that: Should I use UsersController as an object in "can" method if I do not have a handy one of type User? To applicate it later by "authorize! :show, UsersController" in the "index" method of the controller. Or it should be done in some other way? Thank you for your suggestions.


Solution

  • No you don't want to add the UsersController to CanCan.

    CanCan is meant to authorize resources, not Rails Controllers.

    I would suggest the following:

    def initialize(user)
      if user.is_admin?
        can :manage, User
      else
        can :manage, User, :id => user.id
      end
    end
    

    This would allow the user only access to his own user unless he is an admin. See the Defining abilities page in CanCan Wiki