Problem/Motivation
Opening this as a replacement issue for #2503429: Allow both AJAX and non-AJAX forms to POST to dedicated URLs since it's a completely new approach to the same problem, will mark that issue postponed on this one. Mostly summarising in-person (and slack) discussions with Fabianx at DrupalCon Lille here.
Render caching is completely disabled on POST requests, because our form detection logic relies on re-rendering the entire page to discover where the submitted form is in the render array.
Steps to reproduce
Proposed resolution
Add a 'form' cache tag to all forms.
During a POST request, look for deny-listed cache tags like 'form'.
If on a cache get (during a POST) you encounter such a cache tag, the item is treated as a cache miss (like we do now for render cache gets on POST requests).
All other cache items can be returned from the render cache.
We would continue to not SET render cache data during a POST request.
This will allow the current 're-render the forms to find the one that was submitted' logic to work, without changes, but without having to render the entire page - we'd only do rendering for any forms.
One important thing is that big_pipe and other placeholder render strategies needs to be disabled - so placeholders need to be executed as part of the main page request still.
Once the above is implemented, this will already start working for forms in blocks, so is independently useful.
To actually make it work for forms in the main page content, each form needs to be built inside a lazy builder, probably need to opt-in one by one. Forms can still be max-age=0 if they're in a lazy builder (but could also be cached), other forms that are max-age 1 but not in a lazy builder will work too, because they're also not cached.
Couple of questions that came to mind but I didn't get a chance to discuss with Fabianx:
When we submit the form, by 'breaking' the render cache for it on POST, we'll be treating the existing cache item as invalid. Two questions for this - do we need to prevent the render cache item being set back, and if so, is it OK if we don't actually invalidate the form at all, and leave whatever's in the render cache valid for the next GET request? I think that probably is OK unless the form has a different cache tag that should also invalidate it, and that cache tag would be invalidated when we actually submit the form, which will be after it's been (re-) rendered, but would be good to validate this (no pun intended).
Fabianx:
Great question!
- For Ajax FORMs the form execution is completely interrupting the page render execution by throwing the Exception, so it will not in any case store cache items.
- For normal forms it's more tricky, we want the result definitely not be cached as it could contain e.g. validation messages.
- So on POST we don't do render cache sets, is probably a really good rule. (Now we do neither get nor set, after this patch we only allow GET under certain circumstances) [updated above]