Skip to content

Selective permissions on STI sub-classes not respected by accessible_by #809

Open
@owst

Description

@owst

Steps to reproduce

Granting read permission on a subset of STI subclass doesn't lead to relevant records being returned by accessible_by. With the following STI hierarchy:

class Vehicle < ActiveRecord::Base
class Car < Vehicle
class Motorbike < Vehicle
class Ferrari < Car
class Suzuki < Motorbike

Given can :read, Ferrari we expect Vehicle.accessible_by(ability, :index) to include any instances of Ferrari (but none of Suzuki), but instead no Vehicle records are returned.

Reproduction:

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'
  gem 'rails', '= 6.1.7'
  gem 'cancancan', '= 3.4.0', require: false # require false to force rails to be required first
  gem 'sqlite3'
end

require 'active_record'
require 'cancancan'
require 'minitest/autorun'
require 'logger'

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :vehicles, force: true do |t|
    t.string :type
  end
end

class Vehicle < ActiveRecord::Base; end
class Car < Vehicle; end
class Motorbike < Vehicle; end

class Ferrari < Car; end
class Suzuki < Motorbike; end

class Ability
  include CanCan::Ability

  def initialize
    can :read, Ferrari
  end
end

class BugTest < Minitest::Test
  def test_bug
    ferrari = Ferrari.create!
    suzuki = Suzuki.create!

    ability = Ability.new

    # These assertions pass
    assert_equal true, ability.can?(:index, Ferrari)
    assert_equal false, ability.can?(:index, Suzuki)

    # This assertion passes
    assert_equal [ferrari], Ferrari.accessible_by(ability, :index).to_a
    # This assertion also passes
    assert_equal [ferrari], Car.accessible_by(ability, :index).to_a
    # This assertion fails (the actual array is empty)
    assert_equal [ferrari], Vehicle.accessible_by(ability, :index).to_a
  end
end

This feels like an extension of #677

Expected behavior

The allowed subclass instances should be returned by klass.accessible_by for all klasses in the STI hierarchy.

Actual behavior

The allowed subclass instances are not returned by accessible_by when invoked on the base class.

System configuration

Rails version: 6.1.7

Ruby version: 2.7.6

CanCanCan version 3.4.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions