How to integrate CanCan with multiple devise models?
Asked Answered
E

3

13

How would I go about defining abilities for several devise models?

Ebby answered 18/6, 2012 at 18:25 Comment(0)
I
18

Let's assume your app has two separate Devise-powered user models called User and Admin. This means you use methods like current_user and current_admin side by side.

Let's further assume that you only have/want a single Ability class, which contains all your CanCan permission settings...

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    case user
    when User
      can :create, Comment
      can :read, :all
    when Admin
      can :manage, :all
    end
  end
end

This is exactly what others have proposed, but there's another step you have to take.

By default, CanCan assumes that the method current_user exists and will return a User object to compare with your Ability settings. However, our admin users can be found using current_admin. Without telling CanCan where to find admin objects, they never get reviewed, and thus never get permissions; we must change the defaults when dealing with an admin.

Add the following to application_controller.rb...

def current_ability
  if admin_signed_in?
    @current_ability ||= Ability.new(current_admin)
  else
    @current_ability ||= Ability.new(current_user)
  end
end

Now our Ability class will look at the Admin object if one is available, and fall back on a normal User when none is present.

Further development allows us to move Admin permissions into their own separate Ability class...

def current_ability
  if admin_signed_in?
    @current_ability ||= AdminPowers.new(current_admin)
  else
    @current_ability ||= Ability.new(current_user)
  end
end

For more info, see Changing Defaults in the Wiki. Kudos to Stefan for pointing me at the proper article.

FYI -- CanCan is dead, long live CanCanCan! Up to date with bug fixes and new features. Same namespaces, so it's just a drop-in gem replacement in your Gemfile.

gem 'cancancan', '~> 1.8'
Interfluve answered 21/5, 2014 at 0:49 Comment(1)
after searching i finally found the complete answerCheney
D
3

This worked for me -

class Ability
  include CanCan::Ability

  def initialize(user)
    if user.is_a?(Admin)
      can :manage, :all
    elsif user.is_a?(User)
      can :create, Comment
      can :read, :all
    else
      can :read, :all
    end
  end
end
Despoliation answered 27/9, 2012 at 2:27 Comment(0)
S
2

The current user model is passed to the Ability#initialize, so you can just check its class:

class Ability
  include CanCan::Ability

  def initialize(model)
    case model
    when Admin
      can :manage, :all
    when User
      can :create, Comment
      can :read, :all
    else
      can :read, :all
    end
  end
end
Scorpius answered 18/6, 2012 at 23:17 Comment(2)
Thank you Stefan. Unfortunately, it doesn't seem to be working. It applies only the User case and else but not the Admin. Whenever I login as an admin I only have guest privileges. Probably I'm doing something wrong but I can't figure out.Ebby
Maybe Ability#initialize is not being called for your Admin. Add some logging and check out Changing Defaults.Scorpius

© 2022 - 2024 — McMap. All rights reserved.