-
-
Notifications
You must be signed in to change notification settings - Fork 642
Open
Description
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
endD, [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
Metadata
Metadata
Assignees
Labels
No labels