Module: CrudComponents::Permission

Defined in:
lib/crud_components/permission_context.rb

Overview

Shared evaluation of ‘if:`/`editable:` options on attributes and actions. A callable may depend on the ability (`can?` is available in its context), the record (a one-arity lambda / `it`-proc receives it), or both:

if: ->(book) { can?(:edit, book) && book.published? }

‘recordless:` is what a record-dependent condition evaluates to when there is no record to decide about — a column-level / strong-params check, where the lambda can’t run (it would hit ‘nil`). It is `true` for visibility (`if:` — show the column; the record/form surfaces still apply the per-record decision) and `false` for editability (`editable:` — a class-level permit list must not grant per-record write access, so stay safe). Ability-only conditions (Symbol, zero-arity lambda) don’t need a record and are evaluated regardless.

Class Method Summary collapse

Class Method Details

.permitted?(condition, model, context, record = nil, recordless: true) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/crud_components/permission_context.rb', line 33

def permitted?(condition, model, context, record = nil, recordless: true)
  return true if condition.nil?

  case condition
  when Symbol
    # Sugar for can?(symbol, record) — the record being decided about — so a
    # symbol matches the derived action check (can?(:edit, @book)). For a
    # column-level decision there is no record, so fall back to the model
    # class (can?(symbol, Book)).
    context.can?(condition, record || model)
  when Proc
    if condition.lambda? && condition.arity.zero?
      context.instance_exec(&condition)          # ability-only — no record needed
    elsif record.nil?
      recordless                                 # record-dependent, but nothing to decide on
    else
      context.instance_exec(record, &condition)  # receives the record; can? still in scope
    end
  else
    if !condition.respond_to?(:call)
      !!condition
    elsif record.nil?
      recordless
    else
      condition.call(record)
    end
  end
end