Rails cancan authorizing nested resources - ruby-on-rails

I have Projects resource which is nested in Users resource.
My Cancan Ability class is:
class Ability
include CanCan::Ability
def initialize(user)
#everyone
can :read, Project
if user.blank?
# guest user
...
else
#every signed in user
case user.role
when User::ROLES[:admin]
#only admin role user
can :manage, :all
when User::ROLES[:member]
#only member role user
can :update, User, :id => user.id
can [:create, :update, :destroy], Project, :user_id => user.id
else
end
end
end
end
And Projects controller:
class ProjectsController < ApplicationController
load_and_authorize_resource :user
load_and_authorize_resource :projects, :through => :user, :shallow => true
...
end
I have few questions:
Is it possible to deny :read User and allow to :read Project, so that everyone could access /users/10/projects, but not /users/10 or /users?
How can I deny user accessing :new action with other user_id? For example, if I add
#everyone
can :read, User
can :read, Project
this code allows user with id 42 to access /user/41/projects/new.

Solved it by doing:
class Ability
include CanCan::Ability
def initialize(user)
#everyone
can :read, Project
can :read, User # required to access nested resources
cannot :index, User
cannot :show, User
if user.blank?
# guest user
...
else
#every signed in user
case user.role
when User::ROLES[:admin]
#only admin role user
can :manage, :all
when User::ROLES[:member]
#only member role user
can :update, User, :id => user.id
can :manage, Project, :user => { :id => user.id }
else
end
end
end
end

Related

Allow creation of a limited user only with CanCanCan

I want the Admin user to not have the ability to create users with the role of Super Admin but still be able to create other Admins and Regular Users. How do I accomplish this? Here is my Ability.rb:
class Ability
include CanCan::Ability
def initialize(user)
if user.super_admin?
can :manage, :all
elsif user.admin?
can :manage, [Article, Comment]
can [:destroy, :update], User, :role_id => 2 # If Admin
can [:destroy, :update], User, :role_id => 3 # If User
can :read, User
can :create, User
elsif user.user_regular?
#cannot :read, ActiveAdmin::Page, :name => "Dashboard"
#can :manage, :all
end
end
end
Use cannot with in admin block like cannot :creat, User, :role_id => 1 # let 1 is super admin role id. You can get more info about combine ability at here

cancancan load_and_authorize_resource NameError

I use the CanCanCan, Devise and Rolify gem to for authentication and permission management. But when I create a new controller I got this message:
NameError in PanelController#dashboard
uninitialized constant Panel
My PanelController:
class PanelController < ApplicationController
load_and_authorize_resource
def dashboard
end
end
When I remove this line: load_and_authorize_resource
the Route works. But I can access it without authentication. Do I need a PanelModel to use it?
My AbilityModel is this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
alias_action :create, :read, :update, :destroy, :to => :crud
if user.has_role? :admin
can :manage, :all
elsif user.has_role? :user
can [:read], User
can [:update, :edit], User do |account|
account.email == user.email
end
else
# can :read, :all
can [:create, :new], User
end
end
end
Yesterday my Code works great but today I don't know why I get this error.
Maybe anyone can help me.
My Routes are this for the Controller:
devise_scope :user do
authenticated :user do
# Rails 4 users must specify the 'as' option to give it a unique name
root :to => "panels#dashboard", :as => :panel
end
unauthenticated do
root 'devise/sessions#new', as: :unauthenticated_root
end
end
You can use CanCanCan without a corresponding model using authorize_resource :class => false like this
class PanelController < ApplicationController
authorize_resource :class => false
def dashboard
end
end
and then in your ability:
elsif user.has_role? :user
can :dashboard, :panel

Cancan :create ability

I have the following code:
#/app/models/users/user.rb
class Users::User < ActiveRecord::Base
has_many :phones, class_name: "Users::Phone"
end
#/app/models/users/phone.rb
class Users::Phone < ActiveRecord::Base
belongs_to :user, class_name: "Users::User"
attr_accessible :phone
end
#/app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
can :read, :all
unless user.nil? #logged_in
if user.is? :admin
can :manage, :all
else
can :create, Users::Phone, user_id: user.id
end
end
end
end
I wanna check ability for create only their own phones for users
#/app/views/users/users/show.html.slim
- if can? :create, Users::Phone.new
a[href="#{new_user_phone_path(#user)}"] Add phone
Thats does not work, because I should pass user_id to phone model (like Users::Phone.new user_id: user.id), but I can't do that since Phone's mass assignment.
So how I can check :create phones ability for users?
I do something similar to this in my app by making Ability aware of the underlying parameter structure. You have a few options depending on your requirements. So in your controller you'd have approximately:
def create
#phone = Users::Phone.new(params[:users_phone])
# Optional - this just forces the current user to only make phones
# for themselves. If you want to let users make phones for
# *certain* others, omit this.
#phone.user = current_user
authorize! :create, #phone
...
end
then in your ability.rb:
unless user.nil? #logged_in
if user.is? :admin
can :manage, :all
else
can :create, Users::Phone do |phone|
# This again forces the user to only make phones for themselves.
# If you had group-membership logic, it would go here.
if phone.user == user
true
else
false
end
end
end
end

Cancan user permission?

I am using cancan for permissions and I would like it so users cannot see other users when visiting their profile/users page. User should only be able to see themselves.
In my ability.rb file I have
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.role? :admin
can :manage, :all
elsif user.role? :rookie
can [:update, :destroy], [Album, Photo, User]
can :read, :all
end
can :manage, Album, :profile => { :user_id => user.id }
can :manage, Photo, :profile => { :user_id => user.id }
can :manage, Video, :profile => { :user_id => user.id }
can :manage, Comment, :blog => { :profile => { :user_id => user.id } }
can :manage, User, :id => user.id
end
end
In my users_controller I have
class UsersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def index
#user = current_user
end
def show
#user = User.find(params[:id])
end
end
The above usually works but since user is the primary model I am not sure how I can resolve this. Rails gives me the error
undefined method `user_id'
It should be:
#ability.rb:
can :manage, User, :id => user.id
I am assuming that most users start with role :rookie and you have ability
can :read, :all
for users with role :rookie. Then this means that all :rookie users will be able to read
all resources.

CanCan gem | cannot :index, User

Very basic user model, I wish the admin user to :manage all
else cannot :index, User and some other options, but when I try and block non admin users from viewing the user index, the admin user also has not access.
this is my ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new #guest user
can :manage, :all if user.role == "admin" #if user.admin? can :manage, :all
can :assign_role, User
else
can :read, :all
can :create, User
cannot :assign_role, User
cannot :index, User
can [:show, :edit, :update], User do |current_user|
user.id == current_user.id || user.role == "admin"
end
end
end
What can I do to stop all users being blocked from User index?
Regards
Dan
Something wrong with if-else in code.
if user.role == "admin"
can :manage, :all
can :assign_role, User
else
can :read, :all
can :create, User
cannot :assign_role, User
cannot :index, User
can [:show, :edit, :update], User do |current_user|
user.id == current_user.id || user.role == "admin"
end
end
And also you don't have to deny non-admin user to assign role obviously (cannot :assign_role, User).

Resources