I'm relatively new to rails (3), and am building an application, using CanCan, where there are 3 tiers of users.
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!
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With