I was wondering how I can define an ability class and serve that ability class depending on the user that has logged in.
I am using Active Admin, Can Can and Devise and I have successfully created a User and an AdminUser models.
I have this in my ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if (user)
can :manage, Item
end
end
end
Now I have used this wiki entry to determine that we can indeed define a custom ability file and use that instead of the ability.rb:
https://github.com/ryanb/cancan/wiki/changing-defaults
But what I wanted to do is, be able to use ability.rb if a "non-admin user" is signed in and a custom abilty if a user admin is signed in.
Side Question: Could it be done such that I don't need a custom one and I could set permissions in one ability.rb file?
I've never really used ActiveAdmin, so I'm not entirely sure if I'm missing something, but it doesn't seem like that framework relies on CanCan. That's why I'm assuming you're defining a current_ability method like explained in the wiki and it's instantiated with Ability.new(current_user).
If that's the case, and your current_user can be either a User or an AdminUser, then there's no problem in checking for that in the Ability class:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.kind_of? AdminUser
can :manage, Item
elsif user.kind_of? User
can :read, Item
end
end
end
You can simply take a look at the user's type and change the rules accordingly. You can also use is_a? instead of kind_of? for stricter checking, but it's probably not required and might cause issues if you decide to do inheritance later on.
Another way you could check is by defining an admin? method in both models. This might be a better way to do it, since explicit type checking is not very popular in ruby -- it often limits your choices. It might look like this:
class User < ActiveRecord::Base
def admin?
false
end
end
class AdminUser < ActiveRecord::Base
def admin?
true
end
end
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.admin?
can :manage, Item
else
can :read, Item
end
end
end
Related
I'm working on my abilities model on my Rails app to define my user authorization/abilities using cancancan. At the moment, here's what my ability.rb file looks like this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
else
can :manage, Application
can :read, User
end
end
end
I'm testing my app now. when I log into an account that doesn't have the admin boolean and go to to say /users, they can access that page, but clicking the show buttons or anything else leads them to the root page and says that they don't have permission. Currently I have an Applications controller/model (poor naming convention, realized later). But I simply wanted to make it so that any user who has a boolean FALSE for if they're admin has different abilities. I want the admin? true person to be able to do anything, but I want everyone else to be only able to SEE THEIR OWN own application (not everything entered by all users), only be able to create one application, and only be able to see their own information on the user show page, and only be able to edit their own user information. Can anyone explain how to specify for the things only the users create and such? Thank you!
define role column into your database and insert following line into your model
generate migration:
class AddRoleToUser < ActiveRecord::Migration
def change
add_column :users, :role, :integer
end
end
insert this into your model like (User.rb)
enum role: [:Admin, :Client, :Enduser, :ClientUser, :Moderator]
then you can manage your permission using cancancan
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
else
can [:new,:create, :update, :destroy], User
end
end
end
In CanCan, an ability is assigned to an individual user. Is there a way to access that user when you have an ability record.
I'd like to be able to say:
#ability = Ability.new(User.find(3))
#ability.based_on_user # Does not exist, but would respond with the same thing as User.find(3)
In my app, users can impersonate other users, which involves resetting #current_ability = Ability.new(#impersonated_user) and I'd like to be able to quickly get that user for debugging purposes. The documentation doesn't give any such method, but I would be okay with a hack, since it's just for my own purposes in testing.
Just add that method yourself to your ability model. Something like this:
# in app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
#user = user
# the rest of your code
end
def based_on_user
#user
end
end
In my rails application, my user is able to login once and switch between accounts as they please. When they do, I need to reinitialize their abilities since the permissions are set at the account level in the database.
My initial thought is to initialize the ability class when I detect a change in the account but not sure how to accomplish this.
I am of course open to any other idea. I am new to CanCan.
The Ability class is where all user permissions are defined.
Example:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
else
can :read, :all
end
end
end
The 'can' method is used to define permissions and requires two arguments. The first one is the action you're setting the permission for, the second one is the class of object you're setting it on.
I have a User Model, with a admin boolean field. I then have an Admin Controller which I want CanCan On.
How do I add CanCan to the Admin Controller as there is not Admin Model?
I've tried:
class AdminController < ApplicationController
load_and_authorize_resource :user
load_and_authorize_resource :admin, :through => :user
class Ability
include CanCan::Ability
def initialize
....
can :manage, Admin if current_user.admin == TRUE
....
But that errors with "Access denied on nil"
Ideas? Thanks
Are you sure you have access to the 'current_user' method in your ability class? I wouldn't think you would have.
For what I remember when using CanCan you could have this in your Ability class:
def initialize(user)
user ||= User.new #guest user.
...
end
And the user would be the current user, I expect. And I guess that should work.
You can also take a look at this page: https://github.com/ryanb/cancan/wiki/Non-RESTful-Controllers of the CanCan wiki. It's not exactly the same issue, but as it covers a special case (Non-RESTful-Controllers) it might give you some hints about how to do what you want to do.
Cheers
I'm following the tutorial from Ryan B, but I got something wrong when trying to inspect the user's role.
Why I got a nil initialize parameter when I inspect it. Are there any connection between the initialize parameter with the Person Object, in Ryan's tutorial is using 'user' parameter on initialize method and User Model. Am I forgetting something basic here? These are my codes, Thanks!
class Ability
include CanCan::Ability
def initialize(person)
raise person.inspect
can :read, :all
end
end
Most likely there is no logged in user when you are running this code. You need to create some sort of guest user to check permissions against non logged in users
def initialize(person)
user ||= User.new
if user.role? :somerole
can :read, :all
else
#whatever guest can do
end
end