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.
Related
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
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
I have a db setup where there are many users, which have roles of member or admin. Each user has many cars. Each car has many timeslips
So, how do i limit a user's ability to edit a Timeslip only if he is the owner of the parent car.
In CanCan:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :admin
can :manage, :all
elsif user.has_role? :member
can :manage, Car, :user_id => user.id
can :manage, Timeslip, :car => {:user_id => user.id}
end
end
end
so the line can :manage, Timeslip, :car => {:user_id => user.id} is where i need some help.
Because Timeslip is an association/child of Car, i need to check that its parent car.user_id = the Cancan user.id
I thought how i wrote this is in line with the CanCan docs, but where have I gone wrong?
There might be a shorter way to write it, but this will work:
can :manage, Timeslip do |timeslip|
timeslip.car.user_id == user.id
end
This is what's working for me: can :manage, Timeslip, car: { roles: { id: user.role_ids } }
I'm having some trouble defining permissions for my albums#index action. The path to it is /user/:user_id/albums - this is the ability for my :show action (:read => [:index, :show]) which is working well. The path to it is /user/:user_id/albums/:id/.
can :read, Album do |album|
#user.friends_with?(album.user_id)
end
I'm not sure how to write a similar rule for the index action, or if I even want to use CanCan here. The rule is:
current_user MUST be .friends_with?(user_id) to view any albums belonging to user_id.
user_id is of course taken from params[:user_id]. Note: /user/eml/albums/ would be the path, I'm not fetching users by their .id but by their .username!
class Ability
include CanCan::Ability
def initialize(user)
#user = user || User.new # for guest, probably not needed
#user.roles.each { |role| send(role) }
end
def user
can :read, Album do |album|
#user.friends_with?(album.user_id)
end
can :manage, Album do |album|
album.user_id == #user.id
end
end
end
UPDATE:
Turns out the solution is really simple, I was just not paying attention to my routes:
resources users do
resources albums
end
In the controller that becomes pretty easy then:
load_and_authorize_resource :user, :find_by => :username
load_and_authorize_resource :album, :through => :user
And the rule:
can :read, Album, :user_id => #user.friend_ids # I don't need #user.id
I'm not perfectly happy with it though, as using the user.friends_with?(other_user) method would be much quicker and doesn't have to fetch (potentially) a thousand ids from the database. Any other solution is most welcome.
On IRC you told me that the .roles_mask isn't important... then shouldn't this be something like:
class Ability
include CanCan::Ability
def initialize(user)
if user
can :read, Album, :user_id => [user.id] + user.friend_ids
can :manage, Album, :user_id => user.id
end
end
end
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