Skip to content

Add support for Turbo-streaming ViewComponents via proxy object - #2682

Merged
joelhawksley merged 1 commit into
ViewComponent:mainfrom
bensheldon:bensheldon-render-later
Aug 19, 2026
Merged

Add support for Turbo-streaming ViewComponents via proxy object#2682
joelhawksley merged 1 commit into
ViewComponent:mainfrom
bensheldon:bensheldon-render-later

Conversation

@bensheldon

Copy link
Copy Markdown
Contributor

Replaces #2645 as a freestanding PR. Alternative to #2595. Closes #1106.

@bensheldon
bensheldon force-pushed the bensheldon-render-later branch 6 times, most recently from f079032 to eee0d68 Compare August 18, 2026 23:17
Co-authored-by: Joel Hawksley <joel@hawksley.org>
@bensheldon
bensheldon force-pushed the bensheldon-render-later branch from eee0d68 to f661e83 Compare August 19, 2026 00:30

### Limitations

- Blocks passed to `render_later`, `render_in`, or slot calls raise `ViewComponent::Serializable::UnserializableError`. Use component-based slots instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm feeling torn on this constraint.

On one hand, ViewComponents are generally only passed blocks when rendered inside templates, so this probably isn't a limitation most folks will hit.

But I wonder if we even need to have a proxy at all if we could instead render the component before passing it to broadcast_action_later_to. Yes, you'd be paying the rendering cost inside the callback in your example instead of in a background job, but most ViewComponents should be very cheap to render.

What do you think about taking that approach? FWIW, I am totally fine with your PR as it stands, just wondering if there's something I'm missing about this other potential approach.

@bensheldon bensheldon Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we even need to have a proxy at all if we could instead render the component before passing it to broadcast_action_later_to.

That's what broadcast_to basically does; my intent to support _later is specifically to allow deferring the rendering.

I agree that deferred rendering is not completely transparent: you still have to design the View Componant to be deferrable by ensuring that all of its inputs are serializable (no blocks, procs, unmaterialized active record queries, etc.). But I want to make it possible.

I don't feel very strongly about doing it as a Proxy, or just storing the serialized data inside of the base View Component. I liked the Proxy because I found it easier to extend and have a clear contract of like "this is serializable, everything else isn't" and I felt like made it easier to add functionality, like adding serializable with_ slot methods.

Also, sorta an aside, but I remember DMing about this with @camertron and it doesn't look like it made it into the issue: the tricky bit here is that on a View Component, it's tricky to intercept initialize because the method is defined on the View Component, not the Base, and Collections introspect the arguments (specifically for the _counter argument, but maybe others). The argument introspection makes it tricky to do the other thing I tried, which was simply prepending a module on top with def initialize(...) on inherited. But using ... argument forwarding broke Collection's argument introspection and it felt a lot more heavyhanded/performance-sapping to change the introspection.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had figured you wanted to defer rendering. I think this is fine. Merging!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AWESOME! 🚀

@joelhawksley
joelhawksley merged commit c9dea93 into ViewComponent:main Aug 19, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Turbo-Streaming ViewComponents

2 participants