{"record":{"id":"bb9e8ae990ee82e1","repo":"CanCanCommunity/cancancan","slug":"the-can-and-cannot-call-cannot-be-used-with-a-ra","errorCode":null,"errorMessage":"The can? and cannot? call cannot be used with a raw sql 'can' definition. The checking code cannot be determined for #{action.inspect} #{subject.inspect}","messagePattern":"The can\\? and cannot\\? call cannot be used with a raw sql 'can' definition\\. The checking code cannot be determined for #(.+?) #(.+?)","errorType":"exception","errorClass":"CanCan::Error","httpStatus":null,"severity":"error","filePath":"lib/cancan/ability/rules.rb","lineNumber":63,"sourceCode":"      end\n\n      def possible_relevant_rules(subject)\n        if subject.is_a?(Hash)\n          rules\n        else\n          positions = @rules_index.values_at(subject, *alternative_subjects(subject))\n          positions.compact!\n          positions.flatten!\n          positions.sort!\n          positions.map { |i| @rules[i] }\n        end\n      end\n\n      def relevant_rules_for_match(action, subject)\n        relevant_rules(action, subject).each do |rule|\n          next unless rule.only_raw_sql?\n\n          raise Error,\n                \"The can? and cannot? call cannot be used with a raw sql 'can' definition. \" \\\n                \"The checking code cannot be determined for #{action.inspect} #{subject.inspect}\"\n        end\n      end\n\n      def relevant_rules_for_query(action, subject)\n        rules = relevant_rules(action, subject).reject do |rule|\n          # reject 'cannot' rules with attributes when doing queries\n          rule.base_behavior == false && rule.attributes.present?\n        end\n        if rules.any?(&:only_block?)\n          raise Error, \"The accessible_by call cannot be used with a block 'can' definition.\" \\\n            \"The SQL cannot be determined for #{action.inspect} #{subject.inspect}\"\n        end\n        rules\n      end\n\n      # Optimizes the order of the rules, so that rules with the :all subject are evaluated first.","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/CanCanCommunity/cancancan/blob/8c1bf153a3da7b2261d6fa4a5f84eb28e2feb828/lib/cancan/ability/rules.rb#L45-L81","documentation":"A rule defined with a raw SQL string, e.g. can :read, Project, \"visibility = 'public'\", can only be translated into SQL for queries; there is no way to evaluate a SQL fragment against an in-memory record. Rules#relevant_rules_for_match (lib/cancan/ability/rules.rb:63) therefore raises CanCan::Error whenever can?, cannot?, or authorize! encounters an only_raw_sql? rule for the requested action/subject.","triggerScenarios":"Defining can :read, Article, 'published_at IS NOT NULL' in the Ability and then calling can?(:read, @article), cannot?(:read, @article), authorize! :read, @article, or the controller authorize helper on an instance; the same failure fires inside load_and_authorize_resource for single-record actions (show/edit/update/destroy).","commonSituations":"Using DB-specific SQL fragments (bit masks, function calls like NOW() < expires_at) for permissions and then using view guards <%= can?(:read, @article) %>; converting hash conditions to SQL strings for performance and forgetting that every instance check now explodes; index actions keep working (they compile to SQL) while show actions raise, which confuses debugging.","solutions":["Replace the raw SQL string with an equivalent conditions hash so instance checks work: can :read, Article, published: true.","Use a block for logic that must stay in Ruby: can :read, Article { |a| a.published? } — note this then breaks accessible_by, so prefer the hash when both are needed.","Keep raw SQL only for abilities used exclusively in queries (accessible_by) and never call can? on instances of that subject.","As a last resort, rescue CanCan::Error and fall back to a Ruby-side check for that subject."],"exampleFix":"# before (app/models/ability.rb)\ncan :read, Article, \"published_at <= NOW()\"\n# view: can?(:read, @article) -> CanCan::Error (raw sql cannot be checked)\n\n# after\ncan :read, Article, :published => true            # hash: works for can? AND accessible_by\n# or, if logic must be Ruby-side:\ncan :read, Article, ->(_) { true }, where: 'published_at <= NOW()' # not supported; use block only when accessible_by is never called","handlingStrategy":"validation","validationCode":"# before any instance check on this subject\ndef instance_checkable?(ability, action, subject)\n  klass = subject.is_a?(Class) ? subject : subject.class\n  ability.rules.none? { |rule| rule.only_raw_sql? && rule.relevant?(action, klass) }\nend\n\nraise CanCan::Error, 'raw sql rule blocks can? checks' unless instance_checkable?(current_ability, :read, @article)","typeGuard":"def raw_sql_rule?(rule)\n  rule.respond_to?(:only_raw_sql?) && rule.only_raw_sql?\nend","tryCatchPattern":"begin\n  can?(:read, @article)\nrescue CanCan::Error => e\n  Rails.logger.warn(\"cannot instance-check raw sql rule: #{e.message}\")\n  false # fail closed\nend","preventionTips":["Prefer conditions hashes over SQL strings; SQL strings are for query-only abilities only.","If a SQL-string ability exists for a model, never call can?/authorize on its instances.","Add a spec for every ability asserting can? works on a sample record — it catches raw-sql rules immediately.","Rescue CanCan::Error and fail closed (deny) rather than letting the error 500."],"tags":["raw-sql","conditions","can-predicate","cancancan","ruby"],"backgroundTag":"raw-sql-conditions-unsupported","analyzedSha":"8c1bf153a3da7b2261d6fa4a5f84eb28e2feb828","analyzedAt":"2026-08-21T20:05:55.000Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}