Skip to content

Prevent SelfDrop context mutation across render boundaries#2082

Open
karreiro wants to merge 3 commits intomainfrom
self-drop-renderer-mutation
Open

Prevent SelfDrop context mutation across render boundaries#2082
karreiro wants to merge 3 commits intomainfrom
self-drop-renderer-mutation

Conversation

@karreiro
Copy link
Copy Markdown
Contributor

@karreiro karreiro commented May 6, 2026

This PR fixes SelfDrop scoping so a self assigned in one template preserves its original scope when passed to a rendered template.

# template1.liquid
{% assign var = 42 %}
{% assign s = self %}
{% render 'template2', other_self: s %}

# template2.liquid
{% assign var = 43 %}
{{ other_self.var }}  => 43 (wrong — should be 42)

The fix renames @context to @self_context in SelfDrop, so the drop has a specific reference to its originating context instead of reusing the inherited context that gets overwritten at the context.rb level on line 220.

@karreiro karreiro requested review from aswamy and ianks May 6, 2026 09:01
Copy link
Copy Markdown
Contributor

@aswamy aswamy left a comment

Choose a reason for hiding this comment

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

Not sure if liquid-spec also allows render tags, but ill update it to capture your test. Thank you for this ❤️

0Shopify/liquid-spec#124

Comment thread test/integration/self_drop_context_test.rb
Copy link
Copy Markdown
Contributor

@ianks ianks left a comment

Choose a reason for hiding this comment

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

We likely want to undef context as well, which serves as a signal that the drop doesn’t support contextualization

@karreiro
Copy link
Copy Markdown
Contributor Author

karreiro commented May 8, 2026

Thank you for the review, @ianks!

I did consider undef_method :context=, but that felt a bit unexpected, also because some places (e.g., template.rb:155) call Drop#context= without any guard. I went with def context=(_); end instead to keep the interface intact. Please let me know your thoughts!

@karreiro karreiro force-pushed the self-drop-renderer-mutation branch from 74943a1 to bc7f1ca Compare May 8, 2026 08:11
@karreiro karreiro requested a review from ianks May 8, 2026 08:14
@jg-rp
Copy link
Copy Markdown
Contributor

jg-rp commented May 8, 2026

Hi 👋

This looks like a subtle change in policy for the {% render %} tag. A deliberate mechanism for template authors to bring all of the parent template's scope into a partial template, albeit namespaced under an arbitrary variable.

I understand if you've decided this is a positive new feature. It's just that with this change partial templates are less isolated. They are potentially more tightly coupled to their parent templates, which I thought was one of the reasons for introducing {% render %} and depreciating {% include %}.

And, of course, having arbitrary aliases of self does make static analysis much harder.

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.

4 participants