Skip to content

Fix shared route bindings mutation in _substituteBindings#875

Merged
bakerkretzmar merged 2 commits intotighten:2.xfrom
pataar:fix/bindings-mutation
Mar 5, 2026
Merged

Fix shared route bindings mutation in _substituteBindings#875
bakerkretzmar merged 2 commits intotighten:2.xfrom
pataar:fix/bindings-mutation

Conversation

@pataar
Copy link
Contributor

@pataar pataar commented Mar 5, 2026

When _substituteBindings encounters an object missing its registered binding key (e.g. slug), it falls back to id — but it does so by writing bindings[key] = 'id' directly on the shared route definition. This permanently overwrites the original binding for all subsequent calls.

For example, with a posts.show route bound to slug:

// First call — partial object, no slug, falls back to id
route('posts.show', { post: { id: 1 } });
// 'https://example.com/posts/1' ✓

// Second call — full object with slug
route('posts.show', { post: { id: 1, slug: 'hello-world' } });
// Expected: 'https://example.com/posts/hello-world'
// Actual:   'https://example.com/posts/1' ✗

The second call uses id instead of slug because the first call mutated the route config.

This PR replaces the mutation with a local variable so the fallback is resolved per-call.

When a route parameter object was missing its registered binding key but
had an 'id' key, _substituteBindings would set `bindings[key] = 'id'`
directly on the shared route definition. This permanently changed the
binding for all subsequent calls to that route.

Use a local variable instead so the fallback to 'id' is resolved per
call without mutating the route config.
@bakerkretzmar
Copy link
Collaborator

Wow great catch, thank you!

@bakerkretzmar bakerkretzmar merged commit 673b16e into tighten:2.x Mar 5, 2026
26 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