cancancan load_and_authorize_resource NameError - ruby-on-rails

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

Related

uninitialized constant Ability Rails

I have gone through different solutions given to this problem but none of them is working so please don't try to close the question as duplicate.
I have role column in my users table. So user can by admin or user and I need to put permissions on the base of user Role using CanCan. I want to give all permissions to admin. I am logged in as admin but when I access /users I get the error uninitialized constant Ability and when I remove load_and_authorize_resource my cancan permission doesn't work.My ability class looks like
class Ability
include CanCan::Ability
def initialize(user)
#abort("Message goes here")
user ||= User.new # guest user
#abort('some user')
if user.role == 'admin'
can :manage, :all
elsif user.role == 'user'
can :manage, Micropost do |micropost|
micropost.try(:owner) == user
end
can :update, User do |users|
users.try(:owner) == user
end
else
can :read, :all
end
end
end
In my UsersController I am having
class UsersController < ApplicationController
load_and_authorize_resource
#devise code
before_filter :authenticate_user!, only: [:index, :edit, :update, :destroy, :following, :followers]
blah blah
end
And my routes file looks like
FirstApp::Application.routes.draw do
devise_for :users
resources :users do
member do
get :following, :followers
end
end
#resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
root to: "static_pages#home"
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
end
You are seeing uninitialized constant Ability because the load_and_authorize_resource method in your UsersController expects to find an Ability class.
The solution is to move the file containing your ability definitions to app/models/ability.rb.
#app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
#abort("Message goes here")
user ||= User.new # guest user
#abort('some user')
if user.role == 'admin'
can :manage, :all
elsif user.role == 'user'
can :manage, Micropost do |micropost|
micropost.try(:owner) == user
end
can :update, User do |users|
users.try(:owner) == user
end
else
can :read, :all
end
end
end
I got the same error because of a typo in the action name.
In my case, there was no controller action called test
can [:test], [StaticPage]

ArgumentError in Users::RegistrationsController#new

I am trying to get Cancan to work with Devise on my Rails application. I tried to follow the directions here to set it up:
http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/
I am stuck as I am getting the following error:
ArgumentError in Users::RegistrationsController#new
wrong number of arguments (2 for 1)
app/models/ability.rb:7:in initialize'
app/controllers/users/registrations_controller.rb:6:incheck_permissions'
My ability.rb reads as follows:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :super_admin
can :manage, :all
elsif user.role? :admin
can :manage, :all
elsif user.role? :user
can :read, :all
# 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
My registrations controller reads:
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
end
This only occurs on the signup page. All other pages within the app are working fine.
When using cancan u have to use following line in your controller.
load_and_authorize_resource

Devise and cancan gems: has_many association

I use devise and cancan gems and have simple model association: user has_many subscriptions, subscription belongs_to :user. Have following SubscriptionsController:
class SubscriptionsController < ApplicationController
load_and_authorize_resource :user
load_and_authorize_resource :subscription, through: :user
before_filter :authenticate_user!
def index
#subscriptions = #user.subscriptions.paginate(:page => params[:page]).order(:created_at)
end
#other actions
end
And Cancan Ability.rb:
class Ability
include CanCan::Ability
def initialize(user)
user ||=User.new
can [:read], [Edition, Kind]
if user.admin?
can :manage, :all
elsif user.id
can [:read, :create, :destroy, :pay], Subscription, user_id: user.id
can [:delete_from_cart, :add_to_cart, :cart], User, id: user.id
end
end
end
The problem is that i cannot use subscriptions actions as a user but can as a admin. And have no problems with UsersController. When i delete following lines from SubscriptionsController:
load_and_authorize_resource :user
load_and_authorize_resource :subscription, through: :user
before_filter :authenticate_user!
Have no problems at all. So the issue in these lines or in Ability.rb. Any suggestions?
UPDATE: It's interesting that if i add smth like can? :index, Subscription to html template it displays true. If add smth like can? :index, Subscription.first (subscription of another user) it shows false. Looks like Cancan works normally. But what's the problem?..
UPDATE: If change SubscriptionsControlle like:
class SubscriptionsController < ApplicationController
#load_and_authorize_resource :user
#load_and_authorize_resource :subscription, through: :user
before_filter :authenticate_user!
def show
#user = User.find params[:user_id] #line 1
#subscription = #user.subscriptions.find params[:id] #line 2
#container_items = #subscription.container_items.paginate(:page => params[:page])
authorize! :show, #subscription #line 4
end
#some actions
end
It works perfect and prevent unauthorized user access when need.
Are the lines #1, 2 and 4 not equivalent to commented?..
UPDATE: Have the following in routes.rb:
resources :users, except: [:show] do
member do
get 'cart'
delete 'delete_from_cart' => 'users#delete_from_cart'
post 'add_to_cart' => 'users#add_to_cart'
end
resources :subscriptions do
member do
post 'pay'
end
end
end
UPDATE: Next solution prevent unauthorized access to all of subscriptions actions except index:
class SubscriptionsController < ApplicationController
load_resource :user
load_resource :subscription, through: :user
authorize_resource through: :current_user
before_filter :authenticate_user!
#actions
end
So what's the best way to prevent access to index action?
Found only following solution:
before_filter :authorize_index, only: [:index]
def authorize_index
raise CanCan::AccessDenied unless params[:user_id] == current_user.id.to_s
end
It should be
load_and_authorize_resource :subscription
or just
load_and_authorize_resource
in your case, when you want nested resource, then
load_and_authorize_resource :through => :current_user
see https://github.com/ryanb/cancan/wiki/Nested-Resources

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.

Rails cancan authorizing nested resources

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

Resources