ryanb/cancan — Issue #547: accessible_by and read inconsistent
Author: rockrep
Created: 2012-01-14 20:00:49+00:00
State: open

Hi Ryan. I'm running into an issue where the Model.accessible_by action used in load_resource for #index is returning the correct results, but the #show action is raising an authorization error for some of the same resources returned by #index.

Here's the Ability snippet:
def initialize(user)
can :read, Event, :deleted => false, :private => false
can :read, Event, :deleted => false, :venue_id => user.venues
end

Here's the models structure:
class User
has_and_belongs_to_many :venues
class Event
belongs_to :venue

Here's the data:
user :id => 5 is associated with venue :id => 1
event(:id => 24, :venue_id => 1, :private => true, :deleted => false)
event(:id => 25, :venue_id => 1, :private => false, :deleted => false)

accessible_by (called by load_resource, in my EventsController), runs this SQL (which is correct):
SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
SELECT DISTINCT "venues".* FROM "venues" INNER JOIN "users_venues" ON "venues"."id" = "users_venues"."venue_id" WHERE "users_venues"."user_id" = 5
SELECT "events".* FROM "events" WHERE (("events"."deleted" = 'f' AND "events"."private" = 'f') OR ("events"."deleted" = 'f' AND "events"."venue_id" IN (1)))

which returns both events.

However Ability.new(User.find(1)).can? :read, Event.find(24)
SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 5]]
SELECT DISTINCT "venues".* FROM "venues" INNER JOIN "users_venues" ON "venues"."id" = "users_venues"."venue_id" WHERE "users_venues"."user_id" = 5
SELECT "events".* FROM "events" WHERE "events"."id" = $1 LIMIT 1 [["id", 24]]
=> false

FWIW, it returns true for Event 25.

Why doesn't the event query combine the two ability definitions as accessible_by does? If a resource is available through accessible_by, it should also be available for a simple :read.

Thanks,

Michael