trouble applying conditional #552

Closed
sorens opened this Issue Jan 24, 2012 · 1 comment

2 participants

@sorens

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).

@cmar
Collaborator

Take a look at the wiki page on defining abilities. You can pass the bar into a block and inspect its foo_id. Only return true if foo_id == 1, otherwise return false. https://github.com/ryanb/cancan/wiki/Defining-Abilities

can :read, Bar do |bar|
bar.foo_id == 1
end

@cmar cmar closed this May 15, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment