lib/view_component/capture_compatibility.rb
# frozen_string_literal: true module ViewComponent # CaptureCompatibility is a module that patches #capture to fix issues # related to ViewComponent and functionality that relies on `capture` # like forms, capture itself, turbo frames, etc. # # This underlying incompatibility with ViewComponent and capture is # that several features like forms keep a reference to the primary # `ActionView::Base` instance which has its own @output_buffer. When # `#capture` is called on the original `ActionView::Base` instance while # evaluating a block from a ViewComponent the @output_buffer is overridden # in the ActionView::Base instance, and *not* the component. This results # in a double render due to `#capture` implementation details. # # To resolve the issue, we override `#capture` so that we can delegate # the `capture` logic to the ViewComponent that created the block. module CaptureCompatibility def self.included(base) return if base < InstanceMethods base.class_eval do alias_method :original_capture, :capture end base.prepend(InstanceMethods) end module InstanceMethods def capture(*args, &block) # Handle blocks that originate from C code and raise, such as `&:method` return original_capture(*args, &block) if block.source_location.nil? block_context = block.binding.receiver if block_context != self && block_context.class < ActionView::Base block_context.original_capture(*args, &block) else original_capture(*args, &block) end end end end end