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.
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'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
Here's my Ability.initialize:
user ||= User.new # handle guest user
if user.has_role? :admin
can :manage, :all
elsif user.has_role? :moderator
can :read, :all
can :update, :all do |clazz|
clazz.managed_by? user
end
elsif user.has_role? :participant
can :update, :all do |clazz|
clazz.owned_by? user
end
can :read, :all do |clazz|
clazz.visible_to? user
end
else
raise "Role decoding in Ability fell through"
end
end
My intention is that the key domain classes [User, Round, Participant, Question and Program] all define an owned_by?, managed_by? and a visible_to? method. And that the rules for allowing one of them to be updated or viewed are applied uniformly.
But I believe that statements like:
can :update, :all do |clazz|
clazz.owned_by? user
end
Are not doing what I think because I don't think I even get to the clazz.owned_by? line.
Can someone straighten me out? I looked at the doc and couldn't really connect what it was saying with the technique I am using. Thank You!
I believe :all is simply a symbol and not an iterator through all classes. You can either list them all explicitly like I'm doing here or use this solution to get a list of all models: https://stackoverflow.com/a/516605/2033014
[User, Round, Participant, Question, Program].each do |klass|
can :update, klass, klass.owned_by?(user)
can :read, klass, klass.visible_to?(user)
end
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.