Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safest and Railsiest way in CanCan to do Guest, User, Admin permissions

I'm relatively new to rails (3), and am building an application, using CanCan, where there are 3 tiers of users.

  • Guest - unregistered visitor User
  • registered and logged in visitor
  • Admin - registered and logged in visitor with admin flag

My ability is bog-stock right now, copied from cancan docs, basically defining the guest role and the admin role

class Ability

    include CanCan::Ability

    def initialize(user)
        user ||= User.new # Guest user

        if user.is_admin?
            can :manage, :all
        else
            can :read, [Asana,Image,User,Video,Sequence]
        end
    end

end

I'm looking to add in the user role. Since I'm creating that throwaway user model, I thought about using new_record? to determine if the user is logged in or not. Something like:

class Ability

    include CanCan::Ability

    def initialize(user)
        user ||= User.new # Guest user

        if !user.new_record? and user.is_admin?
            can :manage, :all
        elsif !user.new_record? and !user.is_admin?
            can {registered user-y permissions}
        else
            can :read, [Asana,Image,User,Video,Sequence]
        end
    end

end

But, it just doesn't feel right. Seems kind of disassociated from, like, actual logged-in-ed-ness, and have concerns about whether its actually secure.

Looking for advice on a more elegant way to doing this.

Thanks!

like image 201
Edward M Smith Avatar asked Mar 01 '11 17:03

Edward M Smith


2 Answers

Good question, I use a lower to higher permissions approach:

class Ability  
  include CanCan::Ability  

  def initialize(user)
    # Guest User 
    unless user 
      can :read, [Asana,Image,User,Video,Sequence]
    else
      # All registered users
      can {registered user-y permissions}
      # Admins 
      if user.is_admin?
        can :manage, :all
      end
    end 
  end  
end

This way if tomorrow you have other roles to integrate you can do it adding a case statement like so:

class Ability  
  include CanCan::Ability  

  def initialize(user)
    # Guest User 
    unless user 
      can :read, [Asana,Image,User,Video,Sequence]
    else
      # All registered users
      can {registered user-y permissions}
      # Different roles
      case user.role
      when 'admin'
        can :manage, :all
      when 'manager'
        can :manage, [Video, Image, Sequence]
      end
    end 
  end  
end
like image 200
tommasop Avatar answered Sep 25 '22 16:09

tommasop


So what you basically want is abilities for none logged in users, abilities for a logged in user and then abilities for a logged in admin?

Because the current user model is passed into the initialize you're going to have to test based on a property of the user and it would make sense to use a basic role property stored on the user model, eg

def initialize(user)
user ||= User.new # guest user (not logged in)
if user.role == 'admin'
  # Admin roles
  can :manage, :all
elsif user.role == 'user'
  # Signed in user permissions
else
  # Guest permissions
  can :read, :all
end

end

So when a user signs up/registers you can default the role value to 'user' and then allow for some method to update this to 'admin' in a management interface. You could use a single admin? check on a user since this would be false for guests as well as normal logged in users.

like image 29
John Beynon Avatar answered Sep 25 '22 16:09

John Beynon