{"record":{"id":"af5d6dd3dd63601e","repo":"CanCanCommunity/cancancan","slug":"a-hash-of-conditions-is-mutually-exclusive-with-a","errorCode":null,"errorMessage":"A hash of conditions is mutually exclusive with a block. Check \":#{action} #{subject}\" ability.","messagePattern":"A hash of conditions is mutually exclusive with a block\\. Check \":#(.+?) #(.+?)\" ability\\.","errorType":"exception","errorClass":"CanCan::BlockAndConditionsError","httpStatus":null,"severity":"error","filePath":"lib/cancan/rule.rb","lineNumber":126,"sourceCode":"\n    def matches_subject?(subject)\n      @subjects.include?(:all) || @subjects.include?(subject) || matches_subject_class?(subject)\n    end\n\n    def matches_subject_class?(subject)\n      SubjectClassMatcher.matches_subject_class?(@subjects, subject)\n    end\n\n    def parse_attributes_from_extra_args(args)\n      attributes = args.shift if valid_attribute_param?(args.first)\n      extra_args = args.shift\n      [attributes, extra_args]\n    end\n\n    def condition_and_block_check(conditions, block, action, subject)\n      return unless conditions.is_a?(Hash) && block\n\n      raise BlockAndConditionsError, 'A hash of conditions is mutually exclusive with a block. ' \\\n        \"Check \\\":#{action} #{subject}\\\" ability.\"\n    end\n\n    def wrap(object)\n      if object.nil?\n        []\n      elsif object.respond_to?(:to_ary)\n        object.to_ary || [object]\n      else\n        [object]\n      end\n    end\n  end\nend\n","sourceCodeStart":108,"sourceCodeEnd":141,"githubUrl":"https://github.com/CanCanCommunity/cancancan/blob/8c1bf153a3da7b2261d6fa4a5f84eb28e2feb828/lib/cancan/rule.rb#L108-L141","documentation":"Rule#condition_and_block_check (lib/cancan/rule.rb:126) raises CanCan::BlockAndConditionsError when a single can/cannot call passes BOTH a conditions hash and a block. The two forms are ambiguous for query generation (hash becomes SQL, block is Ruby-only), so CanCanCan refuses to guess; the message names the offending \":action subject\" ability.","triggerScenarios":"can :manage, Project, owner_id: user.id { |p| p.active? }; cannot :destroy, Article, featured: true { |a| !a.draft? } — any rule with hash + block in one call. The rule fails at definition time, so the app breaks the moment the Ability class is instantiated.","commonSituations":"Starting with hash conditions and later tacking on a block for an extra check instead of refactoring; merging two rules during cleanup into one illegal combined call.","solutions":["Keep only the block and move hash checks inside it: can :manage, Project { |p| p.owner_id == user.id && p.active? } (note: breaks accessible_by).","Keep only the hash and encode the extra logic as additional hash/SQL conditions to keep queries working.","If the intent was OR, define two separate rules; if AND with complex logic, use the block form and avoid accessible_by for that subject."],"exampleFix":"# before\ncan :manage, Project, owner_id: user.id { |p| p.active? }\n# -> BlockAndConditionsError\n\n# after (query-friendly)\ncan :manage, Project, owner_id: user.id, active: true\n\n# or (ruby-only, do not call accessible_by on Project)\ncan :manage, Project { |p| p.owner_id == user.id && p.active? }","handlingStrategy":"validation","validationCode":"# wrapper that rejects the illegal combination up front\ndef safe_can(action, subject, conditions = nil, &block)\n  raise ArgumentError, 'conditions hash and block are mutually exclusive' if conditions.is_a?(Hash) && block\n  block ? can(action, subject, &block) : can(action, subject, conditions)\nend","typeGuard":"def hash_and_block?(conditions, block)\n  conditions.is_a?(Hash) && block_given?\nend","tryCatchPattern":null,"preventionTips":["Pick one style per rule: hash (query-friendly), SQL string (query-only), or block (instance-only).","Decide up front whether the subject needs accessible_by; that dictates hash vs block.","Instantiate the Ability in a spec for each role — BlockAndConditionsError fires at definition time and is caught immediately.","During refactors, split combined rules into two rules rather than merging hash + block."],"tags":["rule-definition","conditions","block","cancancan","ruby"],"backgroundTag":"mutually-exclusive-arguments","analyzedSha":"8c1bf153a3da7b2261d6fa4a5f84eb28e2feb828","analyzedAt":"2026-08-21T20:05:55.000Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}