I'm using CanCan & Devise for user authentication & permissions.
A user can nominate a keyholder for their account, who will have different permissions. The keyholder has an attribute called 'access_id' that is the same as the id of the account they can access. What I'm trying to acheive is the following:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.admin?
can :manage, :all
elsif user.keyholder?
can :read, Folder do |folder|
folder.try(:user) == user.access_id
end
else
can :create, :all
can :manage, :all do |all|
all.try(:user) == user
end
end
end
end
But with this code, the keyholder cannot access the account they are nominated to access. How do I rectify the code to make this happen? Thanks!
you can try
folder.user_id == user.access_id
assuming keyholder is logged in.
so that
user.keyholder? => true
user => keyholder
user.access_id => id of user who did nominate current_user
folder.user_id => id of folder owner
edit
if you also want that keyholder also accesses his / her folder:
( folder.user_id == user.access_id ) || ( folder.user_id == user.id )
but this one is better, put this out of your if / else statements, so that anyone, (keyholder, or regular user) can acess his / her own folder.
def initialize(user)
user ||= User.new # guest user
# every one reads his own folder.. or you can copy this to wherever you want
can :read, Folder do |folder|
folder.user_id == user.id
end
if user.admin?
can :manage, :all
elsif user.keyholder?
can :read, Folder do |folder|
# but keyholder accesses even more
folder.user_id == user.access_id
end
else
can :create, :all
can :manage, :all do |all|
all.try(:user) == user
end
end
end
also, alternatively, you can define can :read for keyholder multiple times. like:
elsif user.keyholder?
can :read, Folder do |folder|
folder.user_id == user.access_id
end
can :read, Folder do |folder|
folder.user_id == user.id
end
else
Related
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
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.
I am new to Rails and am having troubles figuring out how to create user roles and then have it working with Cancan. I am following rails cast on this and the cancan wiki. What I don't understand to do is define each user role, for example what the admin, registered member and guest can access. I'm not sure if I'm on the right path or not with my coding. I have also run into a "undefined local variable or method `roles_mask'" error.
I don't believe I have the roles set proper in the below file. I have created user authentication from scratch if that helps any. The sections I have so far are galleries and user profile. ATM if I create a new account and select drop down box option "admin", I don't have any admin powers. I am still lock out of accessing pages.
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if #user && #user.role?(:admin)
can :manage, :all
else
can :read, :all
end
if user.role? :user
can :manage, Profile
end
if user.role? :admin
can :manage, Profile
end
end
end
user.rb
ROLES = %w[admin user guest banned]
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end
def roles
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end
def role?(role)
roles.include? role.to_s
end
In your ability.rb file,
if #user && #user.role?(:admin)
should probably be
if user && user.role?(:admin)
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.