cancancan icon indicating copy to clipboard operation
cancancan copied to clipboard

hash_condition_match returns nil when subject is ActiveRecord Collection Proxy

Open BookOfGreg opened this issue 5 years ago • 9 comments

When the subject is an ActiveRecord_Associations_CollectionProxy(ActiveRecord::Relation), the inner_foo value is true, but the outer_foo value is nil as seen below;

This is because it calls this method instead of array's any?: https://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-any-3F

screen shot 2018-10-17 at 17 10 56

System configuration

Rails version: 5.2.0

Ruby version: 2.5.1

CanCanCan version 2.3.0

BookOfGreg avatar Oct 17 '18 16:10 BookOfGreg

I'm still struggling to isolate exactly why any? is returning nil, but while debugging it, got a casual segfault from the gem which makes no sense to me so far.

Edit: Turns out using return inside the block in ActiveRecord is causing the segfault. Edit2: See @laurawatson 's reproduction below.

BookOfGreg avatar Oct 17 '18 21:10 BookOfGreg

can you provide a gist to reproduce your issue? Is not clear to me, sorry.

coorasse avatar Oct 18 '18 14:10 coorasse

Here is a reproduction of the issue: https://github.com/laurawatson/can_can_check.

In this reproduction, the issue occurs when you first login as an adviser user and try to access the foo show page. It will redirect you to the home page despite the adviser user having access to foo. If you then head back to the foo show page you will be allowed in (more info in the readme).

laurawatson avatar Oct 19 '18 10:10 laurawatson

@coorasse We're currently effectively having to inline our ActiveRecord conditions to avoid this bug. We suspect it's some unusual interaction between ActiveRecord lazy loading and this gem but I have been unable to diagnose it further than that any? method mentioned previously.

Would you be so kind as to confirm if you see the same issue as us in the example repo linked by @laurawatson above? If it is at least a confirmed bug then we may be able to put some time aside to help fix it, until then all we can do is assume it's our mistake and not use this gem.

BookOfGreg avatar Oct 29 '18 09:10 BookOfGreg

I confirm that I see the same behaviour.

coorasse avatar Feb 21 '19 18:02 coorasse

changing the rule can :read, Foo, user_roles: { user: user } #wrong into can :read, Foo, user_roles: { user_id: user.id } #correct fixes the issue. But I still don't understand why.

coorasse avatar Feb 21 '19 18:02 coorasse

And the user can also see http://cancan_error.localhost:3000/bars/1 which should be protected. By using the id instead of the association name user (which is not supported) fixes it

coorasse avatar Feb 21 '19 19:02 coorasse

It seems like I'm not able to reproduce the issues outlined by @laurawatson.

Manually checking the Foos that the user has access to I was able to record the same behaviour for

can :read, Foo, user_roles: { user: user }

and

can :read, Foo, user_roles: { user_id: user.id }

In addition to that, by using either authorize! or load_and_authorize_resource in controllers/bars_controller.rb I'm not able to access bars/1 with neither {user : user} nor {user_id : user.id }

I guess I must have missed something ^^ Would anyone be so kind as to point me into the correct direction ?

EDIT: Was able to reproduce it ^^ seems that something went wrong during setup

ghost avatar Aug 25 '20 08:08 ghost

@BookOfGreg Interesting thing about the line of code you referenced ^^

By changing:

    attribute.any? { |element| matches_conditions_hash?(element, value) }

to:

    match_results = attribute.map { |element| matches_conditions_hash?(element, value) }
    match_results.any?

It works :D

ghost avatar Aug 31 '20 10:08 ghost