ryanb/cancan — Issue #552: trouble applying conditional
Author: sorens
Created: 2012-01-24 21:54:47+00:00
State: open

I am trying to work with conditional permissions, but I've hit a road block. I have an association where the `bar` model `belongs_to` the `foo` model and `foo` `has_many` `bars`.

What I am trying to do, is through the use of roles (not described here since they don't factor in), is give a user access to a set of `bar` objects based on the `foo` id but not give them access to other `bar` objects.

For the purposes of this report, I've simplified the problem greatly. At this point, all I am trying to do is correctly give everyone access to `bar` objects that have a `foo_id` of `1`. The rspec test at the end has both the positive and negative tests, but no matter what I have tried, I can't seem to give access to `bar` objects with a `foo_id` of `1` without allowing access to `bar` objects with any other `foo_id`. Is it possible? Am I not understanding how the ability precedence works?

# app/models/bar.rb
class Bar < ActiveRecord::Base
belongs_to :foo
end

# app/models/foo.rb
class Foo < ActiveRecord::Base
has_many :bars
end

# app/models/ability.rb
class Ability
include CanCan::Ability

def initialize
cannot :read, Bar
can :read, Bar, :foo_id => 1
can :read, Foo, :id => 1
end
end

# db/schema.rb
ActiveRecord::Schema.define(:version => 20120124212415) do

create_table "bars", :force => true do |t|
t.string "name"
t.integer "foo_id"
t.datetime "created_at"
t.datetime "updated_at"
end

create_table "foos", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end

# spec/models/ability_spec.rb
require 'spec_helper'
require 'cancan/matchers'

describe Ability do
it "one" do
ability = Ability.new
ability.should be_able_to( :read, Bar, :foo_id => 1 )
ability.should_not be_able_to( :read, Bar, :foo_id => 2 )
end
end

When I run the rspec, the above pseudo-code generates

Failures:

1) Ability one
Failure/Error: ability.should_not be_able_to( :read, Bar, :foo_id => 2 )
expected not to be able to :read Bar(id: integer, name: string, foo_id: integer, created_at: datetime, updated_at: datetime) {:foo_id=>2}
# ./spec/models/ability_spec.rb:8

If you need "working" code, I have a new rails project that I created to test this issue in isolation that I could post on Github, though all the important bits are above (I think).