Class: Plutonium::Resource::Policy

Inherits:
ActionPolicy::Base
  • Object
show all
Defined in:
lib/plutonium/resource/policy.rb

Overview

Policy class to define permissions and attributes for a resource. This class provides methods to check permissions for various actions and to retrieve permitted attributes for these actions.

Instance Method Summary collapse

Instance Method Details

#apply_scope(relation, type:, **options) ⇒ Object

Wraps apply_scope to verify default_relation_scope was called. This prevents accidental multi-tenancy leaks when overriding relation_scope.



20
21
22
23
24
25
# File 'lib/plutonium/resource/policy.rb', line 20

def apply_scope(relation, type:, **options)
  @_default_relation_scope_applied = false
  result = super
  verify_default_relation_scope_applied! if type == :active_record_relation
  result
end

#create?Boolean

Checks if the create action is permitted.

Returns:

  • (Boolean)

    false by default.



105
106
107
# File 'lib/plutonium/resource/policy.rb', line 105

def create?
  false
end

#default_relation_scope(relation) ⇒ ActiveRecord::Relation

Applies Plutonium’s default scoping (parent or entity) to a relation.

This method MUST be called in any custom relation_scope to ensure proper parent/entity scoping. Failure to call it will raise an error.

Examples:

Overriding inherited scope while keeping default scoping

# Parent policy has custom filtering you want to replace
class AdminPostPolicy < PostPolicy
  relation_scope do |relation|
    # Replace inherited scope but keep Plutonium's parent/entity scoping
    default_relation_scope(relation)
  end
end

Adding filtering on top of default scoping

relation_scope do |relation|
  default_relation_scope(relation).where(published: true)
end

Parameters:

  • relation (ActiveRecord::Relation)

    The relation to scope

Returns:

  • (ActiveRecord::Relation)

    The scoped relation



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/plutonium/resource/policy.rb', line 62

def default_relation_scope(relation)
  @_default_relation_scope_applied = true

  if parent || parent_association
    unless parent && parent_association
      raise ArgumentError, "parent and parent_association must both be provided together"
    end

    # Parent association scoping (nested routes)
    # The parent was already entity-scoped during authorization, so children
    # accessed through the parent don't need additional entity scoping
    assoc_reflection = parent.class.reflect_on_association(parent_association)
    if assoc_reflection.collection?
      # has_many: merge with the association's scope
      parent.public_send(parent_association).merge(relation)
    else
      # has_one: scope by foreign key
      relation.where(assoc_reflection.foreign_key => parent.id)
    end
  elsif entity_scope
    # Entity scoping (multi-tenancy)
    relation.associated_with(entity_scope)
  else
    relation
  end
end

#destroy?Boolean

Checks if the destroy action is permitted.

Returns:

  • (Boolean)

    Delegates to create?.



126
127
128
# File 'lib/plutonium/resource/policy.rb', line 126

def destroy?
  create?
end

#edit?Boolean

Checks if the edit action is permitted.

Returns:

  • (Boolean)

    Delegates to update?.



156
157
158
# File 'lib/plutonium/resource/policy.rb', line 156

def edit?
  update?
end

#index?Boolean

Checks if the index action is permitted.

Returns:

  • (Boolean)

    Delegates to read?.



135
136
137
# File 'lib/plutonium/resource/policy.rb', line 135

def index?
  read?
end

#new?Boolean

Checks if the new action is permitted.

Returns:

  • (Boolean)

    Delegates to create?.



142
143
144
# File 'lib/plutonium/resource/policy.rb', line 142

def new?
  create?
end

#permitted_associationsArray<Symbol>

Returns the permitted associations.

Returns:

  • (Array<Symbol>)

    An empty array by default.



226
227
228
# File 'lib/plutonium/resource/policy.rb', line 226

def permitted_associations
  []
end

#permitted_attributes_for_createArray<Symbol>

Returns the permitted attributes for the create action.

Returns:

  • (Array<Symbol>)

    The permitted attributes.



172
173
174
175
176
177
# File 'lib/plutonium/resource/policy.rb', line 172

def permitted_attributes_for_create
  autodetect_permitted_fields(:permitted_attributes_for_create) - [
    resource_class.primary_key.to_sym, # primary_key
    :created_at, :updated_at # timestamps
  ]
end

#permitted_attributes_for_editArray<Symbol>

Returns the permitted attributes for the edit action.

Returns:

  • (Array<Symbol>)

    Delegates to permitted_attributes_for_update.



219
220
221
# File 'lib/plutonium/resource/policy.rb', line 219

def permitted_attributes_for_edit
  permitted_attributes_for_update
end

#permitted_attributes_for_indexArray<Symbol>

Returns the permitted attributes for the index action.

Returns:

  • (Array<Symbol>)

    Delegates to permitted_attributes_for_read.



198
199
200
# File 'lib/plutonium/resource/policy.rb', line 198

def permitted_attributes_for_index
  permitted_attributes_for_read
end

#permitted_attributes_for_newArray<Symbol>

Returns the permitted attributes for the new action.

Returns:

  • (Array<Symbol>)

    Delegates to permitted_attributes_for_create.



212
213
214
# File 'lib/plutonium/resource/policy.rb', line 212

def permitted_attributes_for_new
  permitted_attributes_for_create
end

#permitted_attributes_for_readArray<Symbol>

Returns the permitted attributes for the read action.

Returns:

  • (Array<Symbol>)

    The permitted attributes.



182
183
184
# File 'lib/plutonium/resource/policy.rb', line 182

def permitted_attributes_for_read
  autodetect_permitted_fields(:permitted_attributes_for_read)
end

#permitted_attributes_for_showArray<Symbol>

Returns the permitted attributes for the show action.

Returns:

  • (Array<Symbol>)

    Delegates to permitted_attributes_for_read.



205
206
207
# File 'lib/plutonium/resource/policy.rb', line 205

def permitted_attributes_for_show
  permitted_attributes_for_read
end

#permitted_attributes_for_updateArray<Symbol>

Returns the permitted attributes for the update action.

Returns:

  • (Array<Symbol>)

    Delegates to permitted_attributes_for_create.



189
190
191
# File 'lib/plutonium/resource/policy.rb', line 189

def permitted_attributes_for_update
  permitted_attributes_for_create
end

#read?Boolean

Checks if the read action is permitted.

Returns:

  • (Boolean)

    false by default.



112
113
114
# File 'lib/plutonium/resource/policy.rb', line 112

def read?
  false
end

#search?Boolean

Checks if record search is permitted.

Returns:

  • (Boolean)

    Delegates to index?.



163
164
165
# File 'lib/plutonium/resource/policy.rb', line 163

def search?
  index?
end

#send_with_report(method) ⇒ Object

Sends a method and raises an error if the method is not implemented.

Parameters:

  • method (Symbol)

    The method to send.



92
93
94
95
96
97
98
# File 'lib/plutonium/resource/policy.rb', line 92

def send_with_report(method)
  unless respond_to?(method)
    raise NotImplementedError, "#{self.class.name} does not implement the required #{method}"
  end

  public_send(method)
end

#show?Boolean

Checks if the show action is permitted.

Returns:

  • (Boolean)

    Delegates to read?.



149
150
151
# File 'lib/plutonium/resource/policy.rb', line 149

def show?
  read?
end

#skip_default_relation_scope!Object

Explicitly skip the default relation scope verification.

Call this when you intentionally want to bypass parent/entity scoping. This should be rare - consider using a separate portal instead.

Examples:

Skipping default scoping (use sparingly)

relation_scope do |relation|
  skip_default_relation_scope!
  relation.where(featured: true)  # No parent/entity scoping
end


37
38
39
# File 'lib/plutonium/resource/policy.rb', line 37

def skip_default_relation_scope!
  @_default_relation_scope_applied = true
end

#update?Boolean

Checks if the update action is permitted.

Returns:

  • (Boolean)

    Delegates to create?.



119
120
121
# File 'lib/plutonium/resource/policy.rb', line 119

def update?
  create?
end