Module: OpenLoam::PendingActions
- Defined in:
- lib/open_loam/pending_actions.rb
Overview
Staging and reviewing gated mutations (see OpenLoam::PendingAction).
pending = OpenLoam::PendingActions.stage(
summary: "Raise the excavator's daily rate to 1100",
on: equipment, action: :update, changes: { daily_rate: 1100 }
)
pending.preview # => { "daily_rate" => { "from" => 950, "to" => 1100 } }
pending.approve!(by: manager) # role-gated; executes the change
stage NEVER touches the target — it only records the intent. OpenLoam does not
intercept Active Record globally (that would be fragile and out of scope);
this is the primitive a confirm-mode write path calls instead of saving.
Class Method Summary collapse
Class Method Details
.stage(summary:, on:, action:, changes: {}, idempotency_key: nil, actor: OpenLoam::Current.actor) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/open_loam/pending_actions.rb', line 16 def stage(summary:, on:, action:, changes: {}, idempotency_key: nil, actor: OpenLoam::Current.actor) target_type, target_id = resolve_target(on) changes = changes.transform_keys(&:to_s) key = idempotency_key || compute_key(target_type, target_id, action, changes) # The same proposal staged twice collapses to one row — but only a still # PENDING one. A rejected or executed proposal with this key may be # re-staged as a fresh pending row (the partial index allows the coexist). existing = OpenLoam::PendingAction.pending.find_by(idempotency_key: key) return existing if existing OpenLoam::PendingAction.create!( actor_id: actor&.id, action_type: action.to_s, target_type: target_type, target_id: target_id, changeset: changes, summary: summary, idempotency_key: key ) rescue ActiveRecord::RecordNotUnique # Lost a concurrent double-stage race — return the pending row that won. OpenLoam::PendingAction.pending.find_by!(idempotency_key: key) end |