Class: Clickwrap::PendingReceipt
- Inherits:
-
Object
- Object
- Clickwrap::PendingReceipt
- Defined in:
- lib/clickwrap/pending_receipt.rb
Overview
What capture_and! yields to the protected action, before anything has
committed.
It carries the one thing the domain row legitimately needs — a stable
event_id to reference — and deliberately withholds everything else.
Export and verification are unavailable because there is nothing yet to
export or verify: the transaction may still roll back, and an object that
happily serialized itself into a receipt at this point would be describing
evidence that might never exist.
If the transaction does roll back, this object becomes invalid rather than continuing to look like a committed record.
Instance Attribute Summary collapse
-
#event ⇒ Object
readonly
Returns the value of attribute event.
Instance Method Summary collapse
- #actor_reference ⇒ Object
-
#answer_for(statement_key) ⇒ Object
Read the exact answer that this pending event accepted for one statement.
- #answered?(statement_key) ⇒ Boolean
- #committed? ⇒ Boolean
- #declined?(statement_key) ⇒ Boolean
- #event_id ⇒ Object
- #export ⇒ Object
-
#granted?(statement_key) ⇒ Boolean
Consent-oriented convenience predicates.
-
#initialize(event, wait_for_outer_transaction: false) ⇒ PendingReceipt
constructor
A new instance of PendingReceipt.
- #inspect ⇒ Object
-
#mark_committed! ⇒ Object
Internal transaction callbacks.
- #mark_rolled_back! ⇒ Object
- #policy_key ⇒ Object
-
#receipt ⇒ Object
Once the real outermost transaction commits, this same object becomes a truthful handle to the finalized receipt.
- #recorded_at_by_server ⇒ Object
- #rolled_back? ⇒ Boolean
- #statements ⇒ Object
- #subject_fingerprint ⇒ Object
- #to_canonical_json ⇒ Object
- #to_html ⇒ Object
- #to_s ⇒ Object
- #verify ⇒ Object
-
#when_durably_committed(&callback) ⇒ Object
Registers work that is only truthful after the real outer transaction commits.
Constructor Details
#initialize(event, wait_for_outer_transaction: false) ⇒ PendingReceipt
Returns a new instance of PendingReceipt.
19 20 21 22 23 24 |
# File 'lib/clickwrap/pending_receipt.rb', line 19 def initialize(event, wait_for_outer_transaction: false) @event = event @wait_for_outer_transaction = wait_for_outer_transaction @committed = false @rolled_back = false end |
Instance Attribute Details
#event ⇒ Object (readonly)
Returns the value of attribute event.
17 18 19 |
# File 'lib/clickwrap/pending_receipt.rb', line 17 def event @event end |
Instance Method Details
#actor_reference ⇒ Object
29 |
# File 'lib/clickwrap/pending_receipt.rb', line 29 def actor_reference = event.actor_reference |
#answer_for(statement_key) ⇒ Object
Read the exact answer that this pending event accepted for one statement.
Protected domain work often needs it before commit: for example, an
optional consent can enable one preference while an unselected consent
must leave that preference disabled. Reaching through
pending_receipt.event.statements at every call site is both noisy and
dangerously easy to get wrong (an offered-but-unselected option is not a
grant).
Unknown statement keys fail loudly so a typo cannot silently turn into a false boolean at a consequential boundary.
46 47 48 |
# File 'lib/clickwrap/pending_receipt.rb', line 46 def answer_for(statement_key) statement_for(statement_key)&.answer end |
#answered?(statement_key) ⇒ Boolean
50 51 52 |
# File 'lib/clickwrap/pending_receipt.rb', line 50 def answered?(statement_key) statement_for(statement_key)&.answered? || false end |
#committed? ⇒ Boolean
65 66 67 68 |
# File 'lib/clickwrap/pending_receipt.rb', line 65 def committed? refresh_commit_state_if_possible! @committed end |
#declined?(statement_key) ⇒ Boolean
61 62 63 |
# File 'lib/clickwrap/pending_receipt.rb', line 61 def declined?(statement_key) answered?(statement_key) && statement_for(statement_key).action == "declined" end |
#event_id ⇒ Object
26 |
# File 'lib/clickwrap/pending_receipt.rb', line 26 def event_id = event.id |
#export ⇒ Object
101 |
# File 'lib/clickwrap/pending_receipt.rb', line 101 def export(*) = refuse(:export) |
#granted?(statement_key) ⇒ Boolean
Consent-oriented convenience predicates. They inspect BOTH the recorded action and whether the person actually answered, so these methods never reinterpret silence as a grant or decline.
57 58 59 |
# File 'lib/clickwrap/pending_receipt.rb', line 57 def granted?(statement_key) answered?(statement_key) && statement_for(statement_key).action == "granted" end |
#inspect ⇒ Object
103 104 105 106 107 108 109 110 |
# File 'lib/clickwrap/pending_receipt.rb', line 103 def inspect state = if committed? then "committed" elsif rolled_back? then "rolled back" else "uncommitted" end "#<Clickwrap::PendingReceipt #{event_id} (#{state})>" end |
#mark_committed! ⇒ Object
Internal transaction callbacks. Public only because the Event callback invokes them; downstream code gains no authority from calling them—the receipt lookup still requires the event to exist after commit.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/clickwrap/pending_receipt.rb', line 117 def mark_committed! # A non-joinable outer transaction (most visibly Rails' transactional # test wrapper) can make a record-level after_commit fire at a savepoint. # That is not durable finality. Leave the handle pending until no database # transaction is open and the finalized row can be observed afresh. return self if @wait_for_outer_transaction && ::ActiveRecord::Base.connection.transaction_open? return self if @committed @committed = true @rolled_back = false run_durable_commit_callbacks self end |
#mark_rolled_back! ⇒ Object
132 133 134 135 136 137 |
# File 'lib/clickwrap/pending_receipt.rb', line 132 def mark_rolled_back! @committed = false @rolled_back = true @durable_commit_callbacks = [] self end |
#policy_key ⇒ Object
27 |
# File 'lib/clickwrap/pending_receipt.rb', line 27 def policy_key = event.policy_key |
#receipt ⇒ Object
Once the real outermost transaction commits, this same object becomes a truthful handle to the finalized receipt. This matters when Clickwrap joins a host-owned transaction: the capture method has to return before that outer transaction does, so returning a Receipt there would claim a commit that has not happened yet.
92 93 94 95 96 |
# File 'lib/clickwrap/pending_receipt.rb', line 92 def receipt refuse(:receipt) unless committed? Receipt.find(event_id) end |
#recorded_at_by_server ⇒ Object
28 |
# File 'lib/clickwrap/pending_receipt.rb', line 28 def recorded_at_by_server = event.recorded_at_by_server |
#rolled_back? ⇒ Boolean
70 |
# File 'lib/clickwrap/pending_receipt.rb', line 70 def rolled_back? = @rolled_back |
#statements ⇒ Object
32 33 34 |
# File 'lib/clickwrap/pending_receipt.rb', line 32 def statements event.statements.to_h { |statement| [statement.statement_key, statement.action] } end |
#subject_fingerprint ⇒ Object
30 |
# File 'lib/clickwrap/pending_receipt.rb', line 30 def subject_fingerprint = event.subject_fingerprint |
#to_canonical_json ⇒ Object
98 |
# File 'lib/clickwrap/pending_receipt.rb', line 98 def to_canonical_json = refuse(:to_canonical_json) |
#to_html ⇒ Object
99 |
# File 'lib/clickwrap/pending_receipt.rb', line 99 def to_html = refuse(:to_html) |
#to_s ⇒ Object
112 |
# File 'lib/clickwrap/pending_receipt.rb', line 112 def to_s = event_id |
#verify ⇒ Object
100 |
# File 'lib/clickwrap/pending_receipt.rb', line 100 def verify = refuse(:verify) |
#when_durably_committed(&callback) ⇒ Object
Registers work that is only truthful after the real outer transaction commits. Clickwrap's controller adapters use this to clear a registration flow id without clearing it after a savepoint that later rolls back.
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/clickwrap/pending_receipt.rb', line 75 def when_durably_committed(&callback) raise ArgumentError, "when_durably_committed needs a block" unless callback if committed? run_durable_commit_callback(callback) elsif !rolled_back? (@durable_commit_callbacks ||= []) << callback end self end |