Add support for Turbo-streaming ViewComponents via proxy object - #2682
Conversation
f079032 to
eee0d68
Compare
Co-authored-by: Joel Hawksley <joel@hawksley.org>
eee0d68 to
f661e83
Compare
|
|
||
| ### Limitations | ||
|
|
||
| - Blocks passed to `render_later`, `render_in`, or slot calls raise `ViewComponent::Serializable::UnserializableError`. Use component-based slots instead. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I had figured you wanted to defer rendering. I think this is fine. Merging!
Replaces #2645 as a freestanding PR. Alternative to #2595. Closes #1106.