I have an app that has two roles, super and admin. Super can do everything and admin should be able to do everything except categories. I've implemented the following, but it is still allowing access to categories for admin:
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :super
can :manage, :all
elsif user.has_role? :admin
cannot :manage, :categories
can :manage, :all
end
end
If I change it to the below, it locks admin out of everything.
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :super
can :manage, :all
elsif user.has_role? :admin
can :manage, :all
cannot :manage, :categories
end
end
I have load_and_authorize_resource in all of my controllers, but still having no luck figuring it out.
The rules are finally concluded in an array.
In your first example, when you use cannot, such rule got deleted from the array. But then you define can :manage, :all, so the deleted ones recovered.
In the later example, cannot is put at last so the deletion actually have taken effect.
Related
On rails 5. I'm trying to integrate cancancan 3.0.1 with rails_admin (1.4.2) and for the most part it works. My problem is that I can only get routing acccest to work if I give the user can :manage, :all otherwise I get an access Denied from cancancan
Here's my cancancan ability code. In this case the super admin gains access whereas the normal admin with can :manage, Project does not:
class Ability
include CanCan::Ability
def initialize(user)
can :read, :all # allow everyone to read everything
return unless user && user.admin?
can :access, :rails_admin
can :read, :dashboard # allow access to dashboard
if user.superadmin?
can :manage, :all # allow superadmins to do anything
elsif user.admin?
can :manage, Project
end
end
end
Is there anyway to allow users onto this route without manage :all?
I have 5 models in my rails 4 application, and using cancancan gem I want to give access to specific users to a specific model only.
This means:
user1 is allowed to access 1,2 model
user 2 is allowed to access 3,4 model
user 3 is allowed to access all models.
Please guide me.
You should use rolify with cancan to accomplish that. You can assign a certain role with rolify to represent your "user 1" or "user 2" like this:
user = User.find(1)
user.add_role :limited_user_1
and your "user 3" that has access to everything can be an admin
user = User.find(3)
user.add_role :admin
Then with cancan it's as simple as checking if the user has the specified role. In this case :manage means the user has access to all actions, such as :read, :create, :update, :destroy.
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
elsif user.limited_user_1?
can :manage, :model_1
can :manage, :model_2
elsif user.limited_user_2?
can :manage, :model_3
can :manage, :model_4
end
end
end
A simpler version of Mike's answer would be as follows:
#app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
case user.role_id
when 1
can :read, Model
can :read, Model2
when 2
can :read, Model3
can :read, Model4
when 3
can, :manage, :all
end
end
end
You'll have to add a way to define whether a User is 1,2,3 etc, which is why Mike suggested rolify.
I am using cancan to manage authorizations in an activeadmin environment. I have recently used the active_skin gem to improve the looks, but only the super admin with manage:all access could see the new looks. May I know how I could make it visible to others?
Here is a sample Ability file:
if user.is? :admin
can :manage, :all
else
# Admin users can only manage their own posts
can :manage, Post, :organization_id => user.organization_id
end
1- You can use this
can :read, :all
2- Suggest you use new CanCanCan asCanCan no longer updated. Switching is no drama
Pierre
in my application for the User model I have an attribute username (should probably be name). Username is the name the user signs in with. In the sample code below I check if the current user is admin level and then if the username == admin they can manage all else they can only read all. The puts statements are for checking purposes.
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user
if user.is? :admin
puts "-------"
name = user.username
puts "username = " + name.to_s
puts "-------"
if name == "admin"
can :manage, :all
else
can :read, :all
end
elsif user.is? :user
can :manage, Drill
We have a UI that lets admins change permissions on our users. So we store these permissions in the database.
Our ability class is:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :super_admin
can :manage, :all
else
if user.role? :live_trader
can :admin, LiveEvent
end
if user.role? :horse_trader
can :horse_admin, Event
end
if user.role? :channel_admin
can :manage, Channel
end
if user.role? :device_admin
can :manage, Device
end
if user.role? :ost
can :read, Customer.first
end
can do |action, subject_class, subject|
user.roles.find_all_by_action(aliases_for_action(action)).any? do |role|
role.authorizable_type == subject_class.to_s &&
(subject.nil? || role.authorizable_id.nil? || role.authorizable_id == subject.id)
end
end
# can always manage ourselves
can :manage, user
end
end
end
It works fine, except that we can't use accessible_by. We get:
The accessible_by call cannot be used with a block 'can' definition.
I don't see any other way of limiting result sets... Is this a bug or are we doing it wrong?
The error message says it all, really.
There's two ways use cancan using database permissions. One uses the 'can' block, the other uses explicit 'can' permissions. They achieve the same thing.
You can look at https://github.com/ryanb/cancan/wiki/Abilities-in-Database to see the two examples.
I'd say that you'd want to rewrite your 'can' block to:
user.roles.each do |role|
if permission.subject_id.nil?
can permission.action.to_sym, role.authorizable_type.constantize
else
can permission.action.to_sym, role.authorizable_type.constantize, :id => role.authorizable_id
end
end
HTH.
Can you please walk me through the following line of Ruby/Rails?
if user.role? :super_admin
To fit my app, I updated it to:
if user.role? :admin
and that failed, but then I updated it to:
if user.role? == 'admin'
And it works as intended. Why is that?
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :super_admin
can :manage, :all
elsif user.role? :product_admin
can :manage, [Product, Asset, Issue]
elsif user.role? :product_team
can :read, [Product, Asset]
# manage products, assets he owns
can :manage, Product do |product|
product.try(:owner) == user
end
can :manage, Asset do |asset|
asset.assetable.try(:owner) == user
end
end
end
end
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
if user.role? :super_admin
In this line you call the method role? on the object user with the parameter :super_admin (which is a symbol) and check if the method returns true.
If the call to user.role? :admin returns false there might simply be no role named 'admin'.
Reading CanCan's documentation on Role Based Authorization should shed some light on this subject.