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
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
I've added a controller collaborators to manage a particular type of join association between Users and Companies. The issue is that whenever I load anything from collaborators, I get the error
uninitialized constant Collaborator
From my understanding, this is because there is no model Collaborator and I am using cancancanfor authorization. From the old cancan (note not cancancan) documentation, I've been able to gather that controllers that don't have a corresponding model need to have a model manually authorized for them something like: load_and_authorize_resource :the_model, :parent => false.
This seems to work if I disable load_and_authorize_resource in my application.rb controller.
SO my quesestion is: what is the best way to authorize controllers that don't have corresponding models with cancancan? Can I continue to load_and_authorize_resource in my application controller?
Many thanks in advance.
This LINK will help.
From the link, I quote,
class ToolsController < ApplicationController
authorize_resource :class => false
def show
# automatically calls authorize!(:show, :tool)
end
end
And in your ability.rb:
class Ability
include CanCan::Ability
def initialize(user)
can :show, :tool
end
end
How do I allow anonymous users to view the generated XML page for a model with Activeadmin?
../admin/categories.xml
I tried adding skipping the authentication filter with no success.
ActiveAdmin.register Category do
before_filter :authenticate_user!, :except => [:index]
end
Just an update if anyone finds this post. You have to set up Activeadmin with cancan.
https://groups.google.com/forum/?fromgroups#!topic/activeadmin/uJCkRkrrfHY
Remember to use the Activeadmin version from github. When this is configured you will have to initiate a dummy guest user - add this to application_controller.rb
def authenticate_admin_user!
current_user ||= AdminUser.new # guest user
end
Now you will have to configure your cacan permissions
class Ability
include CanCan::Ability
def initialize(user)
if user
can :manage, :all
else
can :read, Category
end
end
end
cancan screencast:
http://railscasts.com/episodes/192-authorization-with-cancan
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
In my application, a user is allowed to assign another user as their "account manager" and the account manager would be allowed to modify all user info. I defined the following ability:
can :manage, User do |user|
user == current_user or user.account_manager == current_user
end
A user also has some nested resources (e.g: publications). I defined the following ability:
can :manage, Publication do |publication, user|
publication.user == current_user or user == current_user or user.account_manager == current_user
end
In the views I check using the following:
can? :update, #publication, #user_we_are_accessing
can? :create, Publication.new, #user_we_are_accessing.
Everything works just fine so far. My problem is with the controller. In my PublicationsController I added:
load_and_authorize_resource :user
load_and_authorize_resource :publication, :through => :user
However this always throws AccessDenied, because the check for publication is not passing the user object to the ability (trying to inspect the user object in the ability shows nil).
Any ideas how I can go about implementing this?
tl;dr: Using CanCan to authorize access to resources. User can assign another user as account manager. User has nested resources. Problem: nested resource is not accessible by account manager.
I solved this by doing the following:
1) replaced load_and_authorize_resource :publication with just loading the resource load_resource :publication
2) Added a before_filter :authorize after the load_resource call with the following implementaiton:
def authorize
raise CanCan::AccessDenied unless can? :manage, #publication, #user
end
This works, but I was hoping for a way that would solve this in the devise way, if there is such a thing. Thoughts and feedback are appreciated.