Skip to content

Commit 367e1ab

Browse files
committed
fix: make the reactive example in the README run
The lead actor declared observable :remaining and the ERB beside it rendered that value in a span while a component observed :holds. Neither worked. A scalar span raises ArgumentError unless the observable is declared broadcast: :value, and a component dependency must itself be a declared observable or ComponentRegistration raises UnknownComponentDependency. remaining now carries broadcast: :value and holds is declared, which is also the clearer teaching example: one observable opts into sending its value to every authorized subscriber, the other only invalidates, which is what the paragraph under it describes. Verified against this branch rather than read: broadcasts_observable_value? is true for remaining, holds resolves as a dependency, and reserve, duplicate reserve, and expire behave as the text claims.
1 parent 499d874 commit 367e1ab

1 file changed

Lines changed: 11 additions & 8 deletions

File tree

README.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ A ticket sale for one event, with 100 seats and a hold that expires:
2222
class TicketSale < SolidObjects::Actor
2323
attribute :remaining, default: 100
2424
attribute :holds, default: -> { {} }
25-
observable :remaining
25+
observable :remaining, broadcast: :value
26+
observable :holds
2627

2728
def reserve(buyer:)
2829
return false if remaining.zero? || holds.key?(buyer)
@@ -176,13 +177,15 @@ least once.
176177
<% end %>
177178
```
178179

179-
`observable :remaining` in the ticket sale is what makes that span live: a
180-
committed turn that changes it replaces the span, and one that changes `holds`
181-
re-renders the component from `actors/ticket_sale/_buyers`. Observables are
182-
invalidation-only unless declared `broadcast: :value`, so only an opted-in
183-
scalar sends its value to every authorized subscriber, and per-viewer state
184-
belongs in `broadcast_payload`. Signed tokens protect integrity, not access:
185-
rendering, Cable, and every refresh each authorize again.
180+
The two observables in the ticket sale are what make that template live: a
181+
committed turn that changes `remaining` replaces the span, and one that changes
182+
`holds` re-renders the component from `actors/ticket_sale/_buyers`. Observables
183+
are invalidation-only unless declared `broadcast: :value`, which is why
184+
`remaining` carries it and `holds` does not: only an opted-in scalar sends its
185+
value to every authorized subscriber, and rendering an invalidation-only
186+
observable as a span raises. Per-viewer state belongs in `broadcast_payload`.
187+
Signed tokens protect integrity, not access: rendering, Cable, and every
188+
refresh each authorize again.
186189

187190
Reactive views require `turbo-rails`, an Action Cable adapter, and
188191
`mount SolidObjects::Engine => "/solid_objects"`. They are optional; the actor

0 commit comments

Comments
 (0)