@@ -246,17 +246,30 @@ def render?
246246
247247 # Re-use original view_context if we're not rendering a component.
248248 #
249- # This prevents an exception when rendering a partial inside of a component that has also been rendered outside
250- # of the component. This is due to the partials compiled template method existing in the parent `view_context`,
251- # and not the component's `view_context`.
249+ # As of v4, ViewComponent::Base re-uses the existing view context created
250+ # by ActionView, meaning the current view context and the original view
251+ # context are the same object. set_original_view_context is still called
252+ # to maintain backwards compatibility.
252253 #
253254 # @private
254255 def render ( options = { } , args = { } , &block )
255256 if options . respond_to? ( :set_original_view_context )
256257 options . set_original_view_context ( self . __vc_original_view_context )
258+
259+ # We assume options is a component, so there's no need to evaluate the
260+ # block in the view context as we do below.
257261 @view_context . render ( options , args , &block )
258262 else
259- __vc_original_view_context . render ( options , args , &block )
263+ __vc_original_view_context . render ( options , args ) do
264+ # Partials are rendered to their own buffer and do not append to the
265+ # original @output_buffer we retain a reference to in #render_in. This
266+ # is a problem since the block passed to us here in the #render method
267+ # is evaluated within the context of ViewComponent::Base, and thus
268+ # appends to the original @output_buffer. To avoid this, we evaluate the
269+ # block in the view context instead, which will append to the output buffer
270+ # created for the partial.
271+ __vc_original_view_context . instance_exec ( &block )
272+ end
260273 end
261274 end
262275
0 commit comments