Why cancancan methods return wrong value in view, but right in controller? - cancancan

I have in cancancan abilities can(:manage, User, id: user.id)
When user opens own profile, then can? :update, #user in the UsersController#show returns correctly true, but in the show view it returns false.
Does anyone know what causes this inconsistency?
cancancan 3.1, rails 6.0.3.4

Ok, I solved it.
The problem was I called can? on decorator and it doesn't work.
can? :update, #user.object works fine.

Related

CanCanCan User edit his own profile

I got a really strange issue here. Here is the line causing all the trouble in my ability.rb
can [:edit, :update, :destroy], User, id: user.id
When I launch the rails console, I got the expected behaviour:
u = User.last
a = Ability.new(u)
a.can?(:edit, u)
=> true
a.can?(:edit, User.first)
=> false
However when I launch a web browser, log me in as a user and try to edit another one, CanCanCan remains silent.
If I replace can by cannot, I can't edit any user. It's as if it didn't lookup the condition.
My UsersController got this line on top
authorize_resource
I'm stuck with this, any help would be gladly appreciated.
cancancan 2.3.0
rails 5.2.1
Make sure that your instance (#user) is loaded before authorize_resource action runs, otherwise it will check if user can access some Users (can?(:edit, User), which is always true), instead of exact user.
before_action :load_user, except:[:index, :new, :create]
authorize_resource
...
private def load_user
#user = User.accessible_by(current_ability, action_name.to_sym).find(params[:id])
end

Ruby on Rails CanCan Gem

I am a bit confused regarding CanCan Gem. I basically understand how to set up abillity.rb. For example lest say we have the following code:
// in abillity.rb
user ||= User.new
can [:update, :destroy, :edit, :read], Book do |book|
book.dashboard.user_id == user.id
end
And then lets say we have the following books controller:
// books_controller.rb
load_and_authorize_resource
def destroy
if can?(:destroy, #book)
#book.destroy!
redirect_to happy_world_path
else
redirect_to not_happy
end
end
My question is: Do we need to check 'can?(:destroy, #book)'?
From my understanding 'load_and_authorize_resource' will not even allow access to this method if we don't have abillity to destroy it.
Yo do not need to add if can?(:destroy, #book) in your action if you use load_and_authorize_resource
Like the README say
Setting this for every action can be tedious, therefore the load_and_authorize_resource method is provided to automatically authorize all actions in a RESTful style resource controller.
If an user without authorization try to destroy, he get a unauthorized response ( not remember if is a 401 code)
Maybe you can use if can?(:destroy, #book) in your views, to do no show thte destroy button. Like also in Check Abilities & Authorization section

In Ruby on Rails Devise: How to Plug Some Code to Handle the Current User When S/he Logs Out

Basically, I want to log something about the current user when s/he logs out.
I am trying to override after_sign_out_path_for:
def after_sign_out_path_for(user)
# Notice that differently from +after_sign_in_path_for+ this method
# receives a symbol with the scope, and not the resource.
# puts current_user.id
new_user_session_path
end
But the method current_user sometimes it returns nil, and from this ticket (https://github.com/plataformatec/devise/pull/2022), it seems current_user is not available in after_sign_out_path_for.
What should I do? Do I have to override other methods? Like: sign_out_and_redirect? Are the any cleaner way to do?
You could try something like:
before_filter :log_user_logout, only: [:destroy]
and access current_user within that method

current_user returns nil even when user_signed_in? returns true

I have devise 2.1.2 and cancan 1.6.8 installed.
The current_user helper from devise works fine in my controllers, but is not working the view templates. I'm confused why this is happening. I've been able to use current_user in my view files before.
I tried adding the before_filter authenticate_user! and that didn't help.
Worse comes to worse, I'll add a before filter to the application_controller that says #current_user = current_user but that seems silly.
It's weird that current_user returns nil while user_signed_in? returns true.
Any thoughts on how to get this resolved?
In the meantime,warden.authenticate(:scope => :user) seems to return the current_user so I'm just going to add that to my application helper.

undefined method current_user: Cancan and Active Scaffold

I'm trying to add an action link to an active scaffold controller using
if current_user.can? :update, Post
config.action_links.add 'export', :label => 'Export', :page => true
end
but whatever controller I try to use, I always get undefined method current_user
So, how can I check if the logged user can/cannot do something?
I've even tried with
def ability
#ability ||= Ability.new(self)
end
delegate :can?, :cannot?, :to => :ability
as suggested here, but without success.
What's wrong with this?
Note that in the normal case ActiveScaffold config is done in the class not the instance so there is no current_user set because there is no request yet.
current_user is a typically defined method, but it is one that you must add. it is not supplied by rails. So, you need a current_user method in your ApplicationController. There are tons of examples but I would look at the authlogic example app on github

Resources