Class: IronAdmin::Policy

Inherits:
Object
  • Object
show all
Defined in:
lib/iron_admin/policy.rb

Overview

Note:

Action aliases are supported:

  • :show and :index are aliases for :read
  • Allowing :read implicitly allows :show and :index
  • Allowing :show or :index is treated as allowing :read

Authorization policy for controlling access to resource actions.

Policies define which actions users can perform on resources. They use a simple DSL with allow and deny to manage permissions.

When no policy is defined for a resource, all actions are allowed by default. Once a policy block is provided, actions must be explicitly allowed. Deny rules take precedence over allow rules.

Examples:

Basic policy in a resource

class UserResource < IronAdmin::Resource
  policy do
    allow :read                           # Everyone can view
    allow :create, :update, if: ->(user) { user.admin? }
    deny :destroy                         # No one can delete
  end
end

Policy with conditional deny

class OrderResource < IronAdmin::Resource
  policy do
    allow :read, :create, :update, :destroy
    deny :destroy, if: ->(user) { !user.superadmin? }
  end
end

See Also:

  • Resource#policy

Constant Summary collapse

ACTION_ALIASES =

Maps controller actions to CRUD operations.

Returns:

  • (Hash{Symbol => Symbol})
{
  show: :read,
  index: :read,
}.freeze
REVERSE_ALIASES =

Reverse mapping from CRUD operations to controller actions.

Returns:

  • (Hash{Symbol => Array<Symbol>})
ACTION_ALIASES.each_with_object({}) do |(action, crud), hash|
  (hash[crud] ||= []) << action
end.freeze

Instance Method Summary collapse

Constructor Details

#initialize { ... } ⇒ Policy

Creates a new Policy instance.

Examples:

Policy.new do
  allow :read
  allow :update, if: ->(user) { user.admin? }
end

Yields:

  • Configuration block using the Policy DSL



59
60
61
62
63
64
# File 'lib/iron_admin/policy.rb', line 59

def initialize(&)
  @allow_rules = {}
  @deny_rules = {}
  @configured = block_given?
  instance_eval(&) if block_given?
end

Instance Method Details

#action_allowed?(action_name, user) ⇒ Boolean

Checks if a custom action (or bulk action) is allowed.

Unlike #allowed?, this does not use action aliases. Custom actions are allowed by default unless explicitly restricted via an allow rule with a condition. This separates custom action authorization from CRUD policy — custom actions are not gated by the CRUD allowlist.

Examples:

policy.action_allowed?(:refund, current_user)

Parameters:

  • action_name (Symbol)

    The custom action name

  • user (Object)

    The current user object

Returns:

  • (Boolean)

    True if the action is allowed, or if no policy is configured, or if the action has no explicit rule



169
170
171
172
173
174
175
176
177
178
# File 'lib/iron_admin/policy.rb', line 169

def action_allowed?(action_name, user)
  return true unless @configured

  action = action_name.to_sym
  return false if denied?(action, user)
  return true unless @allow_rules.key?(action)

  condition = @allow_rules[action]
  condition.nil? || condition.call(user)
end

#allow(*actions, if: nil) ⇒ void

This method returns an undefined value.

Grants permission for one or more actions.

Examples:

Unconditional allow

allow :read

Conditional allow

allow :update, :delete, if: ->(user) { user.admin? }

Parameters:

  • actions (Array<Symbol>)

    Action names to allow

    • CRUD actions: :read, :create, :update, :delete
    • Controller actions: :show, :index (aliased to :read)
    • Custom actions: any symbol matching a defined action
  • if (Proc, nil) (defaults to: nil)

    Optional condition proc that receives the user and returns true if the action should be allowed



82
83
84
85
# File 'lib/iron_admin/policy.rb', line 82

def allow(*actions, if: nil)
  condition = binding.local_variable_get(:if)
  actions.each { |action| @allow_rules[action] = condition }
end

#allowed?(action, user) ⇒ Boolean

Checks if a CRUD action is allowed for the given user.

Handles action aliases automatically:

  • If :show or :index is checked, also checks for :read permission
  • If :read is checked, also checks for :show/:index permissions

Examples:

policy.allowed?(:read, current_user)  #=> true
policy.allowed?(:show, current_user)  #=> true (alias for :read)

Parameters:

  • action (Symbol)

    The action to check (:read, :create, :update, :delete, :show, :index)

  • user (Object)

    The current user object passed to condition procs

Returns:

  • (Boolean)

    True if the action is allowed



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/iron_admin/policy.rb', line 122

def allowed?(action, user)
  return true unless @configured

  # Deny rules take precedence over allow rules
  return false if denied?(action, user)

  # Check the action directly first
  if @allow_rules.key?(action)
    condition = @allow_rules[action]
    return condition.nil? || condition.call(user)
  end

  # Check forward alias (e.g., :show -> :read)
  aliased_action = ACTION_ALIASES[action]
  if aliased_action && @allow_rules.key?(aliased_action)
    condition = @allow_rules[aliased_action]
    return condition.nil? || condition.call(user)
  end

  # Check reverse aliases (e.g., :read -> [:show, :index])
  reverse_actions = REVERSE_ALIASES[action]
  reverse_actions&.each do |reverse_action|
    next unless @allow_rules.key?(reverse_action)

    condition = @allow_rules[reverse_action]
    return condition.nil? || condition.call(user)
  end

  false
end

#deny(*actions, if: nil) ⇒ void

This method returns an undefined value.

Denies permission for one or more actions.

Deny rules take precedence over allow rules. If an action is both allowed and denied, the deny rule wins.

Examples:

Unconditional deny

deny :destroy

Conditional deny

deny :destroy, if: ->(user) { !user.superadmin? }

Parameters:

  • actions (Array<Symbol>)

    Action names to deny

  • if (Proc, nil) (defaults to: nil)

    Optional condition proc that receives the user and returns true if the action should be denied



103
104
105
106
# File 'lib/iron_admin/policy.rb', line 103

def deny(*actions, if: nil)
  condition = binding.local_variable_get(:if)
  actions.each { |action| @deny_rules[action] = condition }
end