CanCanCommunity/cancancan · error · ArgumentError
accessible_by_strategy = :subquery requires ActiveRecord 5 o
Error message
accessible_by_strategy = :subquery requires ActiveRecord 5 or newer
What it means
CanCan.accessible_by_strategy= (lib/cancan/config.rb:71) raises ArgumentError when you set :subquery but the loaded ActiveRecord adapter is older than 5.0 (or the ActiveRecord adapter is not loaded at all, e.g., CanCanCan loaded outside Rails). The subquery strategy relies on 'FROM (subquery) alias' joins introduced in Rails 5, so it cannot work on Rails 4.x.
Source
Thrown at lib/cancan/config.rb:71
@accessible_by_strategy = default_accessible_by_strategy
end
def self.default_accessible_by_strategy
if does_not_support_subquery_strategy?
# see https://github.com/CanCanCommunity/cancancan/pull/655 for where this was added
# the `subquery` strategy (from https://github.com/CanCanCommunity/cancancan/pull/619
# only works in Rails 5 and higher
:left_join
else
:subquery
end
end
def self.accessible_by_strategy=(value)
validate_accessible_by_strategy!(value)
if value == :subquery && does_not_support_subquery_strategy?
raise ArgumentError, 'accessible_by_strategy = :subquery requires ActiveRecord 5 or newer'
end
@accessible_by_strategy = value
end
def self.with_accessible_by_strategy(value)
return yield if value == accessible_by_strategy
validate_accessible_by_strategy!(value)
begin
strategy_was = accessible_by_strategy
@accessible_by_strategy = value
yield
ensure
@accessible_by_strategy = strategy_was
end
endView on GitHub (pinned to 8c1bf153a3)
Solutions
- Stay on the default :left_join strategy when stuck on Rails < 5 (it is the default precisely for this reason).
- Upgrade ActiveRecord/Rails to >= 5.0 to legitimately use :subquery.
- Guard the initializer: only assign when CanCan.valid_accessible_by_strategies.include?(:subquery).
Example fix
# before (config/initializers/cancan.rb) CanCan.accessible_by_strategy = :subquery # ArgumentError on Rails 4.2 # after CanCan.accessible_by_strategy = :subquery if CanCan.valid_accessible_by_strategies.include?(:subquery)
Defensive patterns
Strategy: validation
Validate before calling
strategy = :subquery raise ArgumentError, 'strategy unsupported on this ActiveRecord' unless CanCan.valid_accessible_by_strategies.include?(strategy) CanCan.accessible_by_strategy = strategy
Try / catch
begin
CanCan.accessible_by_strategy = :subquery
rescue ArgumentError => e
Rails.logger.warn("#{e.message}; staying on :left_join")
end Prevention
- Derive the strategy from CanCan.valid_accessible_by_strategies instead of hardcoding it.
- Pin Rails >= 5 in the Gemfile when the app relies on the subquery strategy.
- Run the initializer in CI on the lowest supported Rails version to catch version guards early.
When it happens
Trigger: An initializer containing CanCan.accessible_by_strategy = :subquery in an app on Rails 4.2; a spec_helper that sets the strategy before the ActiveRecord adapter has been required; using CanCan::Config.with_accessible_by_strategy(:subquery) in a gem environment where ActiveRecord 4 is pinned.
Common situations: Copy-pasting the workaround initializer from a PR/blog post for the CanCanCan 619 duplicate-rows bug into a legacy Rails 4 app; CI running a different Rails version than production; loading cancancan in a Ruby-only (non-Rails) test suite.
Related errors
- accessible_by_strategy must be one of #{valid_accessible_by_
- RSpec < 3 will not be supported in the CanCanCan >= 2.0.0
- You are not authorized to access this page.
- You can't specify target (#{target}) as alias because it is
- The can? and cannot? call cannot be used with a raw sql 'can
AI-assisted analysis of CanCanCommunity/cancancan@8c1bf153a3 (2026-08-21).
Data as JSON: /api/errors/926583ec73570008.
Report an issue: GitHub.