Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STI ability overwrites previously defined STI rules #874

Open
23tux opened this issue Jan 14, 2025 · 0 comments
Open

STI ability overwrites previously defined STI rules #874

23tux opened this issue Jan 14, 2025 · 0 comments

Comments

@23tux
Copy link

23tux commented Jan 14, 2025

Steps to reproduce

The order of can statements affects the SQL that is generated:

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"
  gem "rails", "= 7.1.5.1"
  gem "cancancan", "= 3.6.1", 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 Ability
  include CanCan::Ability

  def initialize
    can :index, Vehicle
    can :index, Car
  end
end

class BugTest < Minitest::Test
  def test_bug
    vehicle = Vehicle.create!
    car = Car.create!

    ability = Ability.new

    # These assertions pass
    assert_equal true, ability.can?(:index, Vehicle)
    assert_equal true, ability.can?(:index, Car)
    assert_equal [vehicle, car], Vehicle.accessible_by(ability, :index).to_a
  end
end
D, [2025-01-14T13:10:25.471243 #1978] DEBUG -- :   Vehicle Load (0.1ms)  SELECT "vehicles".* FROM "vehicles" WHERE "vehicles"."type" = ?  [["type", "Car"]]
F

Failure:
BugTest#test_bug [bug.rb:46]:
--- expected
+++ actual
@@ -1 +1 @@
-[#<Vehicle id: 1, type: nil>, #<Car id: 2, type: "Car">]
+[#<Car id: 2, type: "Car">]

Expected behavior

When using Vehicle.accessible_by(ability, :index) I would expect to have access to all vehicles, the generated SQL produces an OR statement in cancancan 3.5.0 but truncates the statement to only include the last defined can :index, XXXX rule.

Actual behavior

Demonstrated best by looking at the SQL:

class Ability
  include CanCan::Ability

  def initialize
    can :index, Vehicle
    can :index, Car
  end
end

Vehicle.accessible_by(Ability.new, :index).to_sql
=> SELECT "vehicles".* FROM "vehicles" WHERE "vehicles"."type" = 'Car'

Switching the order of the can statements:

class Ability
  include CanCan::Ability

  def initialize
    can :index, Car
    can :index, Vehicle
  end
end

Vehicle.accessible_by(Ability.new, :index).to_sql
=> SELECT "vehicles".* FROM "vehicles"

IMO it should not matter, in which order the can statements are written.

System configuration

Rails version: Tested in 7.1 and 7.2

Ruby version: 3.3.3

CanCanCan version 3.6.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant