Skip to content

Fix stale and inherited collection parameter detection; build it at compile time - #2724

Merged
joelhawksley merged 1 commit into
ViewComponent:mainfrom
bensheldon:collection-arguments-ractor-safety
Oct 15, 2026
Merged

joelhawksley merged 1 commit into
ViewComponent:mainfrom
bensheldon:collection-arguments-ractor-safety

Conversation

@bensheldon

@bensheldon bensheldon commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #2722 and #2723 (comment). While working on the collection introspection, I found two caching bugs, and the cached state wasn't Ractor-safe.

  1. A subclass could inherit its parent's default collection parameter name. __vc_collection_parameter stored the computed default into @__vc_provided_collection_parameter, the same ivar with_collection_parameter sets, and inherited copies that ivar to subclasses. So the result depended on load order:

    class ProductComponent < ViewComponent::Base; end
    render(ProductComponent.with_collection(products)) # stores :product on ProductComponent
    
    class SaleProductComponent < ProductComponent       # e.g. autoloaded later in development
      def initialize(sale_product:) = ...
    end
    
    render(SaleProductComponent.with_collection(products))
    # => MissingCollectionArgumentError: ... doesn't accept the parameter `product`

    With eager loading, subclasses usually load before anything renders, so production and development could behave differently.

  2. Recompiling didn't refresh the detection. The memoized parameter names and counter/iteration answers were never cleared, so a forced recompile (e.g. development reloading, or a prepend added after the first render) kept stale results.

Other details

  • With eager loading, the build happens at boot on the main Ractor. After that, everything is read-only and shareable, including the parameter names array, which was previously unfrozen.
  • The four lazy ||= writes are replaced by a single build that runs when the component compiles. If a class hasn’t been compiled yet, the first read builds it, so with eager loading every write happens at boot on the main Ractor.

@joelhawksley
joelhawksley merged commit 96ac9a8 into ViewComponent:main Oct 15, 2026
20 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.

2 participants