Problem/Motivation
Trying to use the pager in the media library modal fails (400), if editing an already-saved node, then used preview and then clicked on "Back to content editing".
Steps to reproduce
- Install Drupal, use the standard profile
- Enable media, media_library
- Add a new 'media reference' field under 'article' bundle; allow referencing unlimited media entities with bundle "Image".
- Create 25+ media/image entities or visit /admin/structure/views/view/media_library/edit/widget and lower the per-page value to ensure the pager will show.
- Create an article node, set a title. Save.
- Edit the just-created node.
- Click on Preview
- Click on "Back to content editing"
- Click on "Add Media"
- Try to load page 2 of the media library
- Notice that a silent failure occurred; checking DevTools/Console, an error is logged about a 400 HTTP response.
The bug reproduces in an existing site running Drupal 9.5.1 with Gin theme.
Proposed resolution
- Set the $node->in_preview flag before ContentEntityForm::submitForm() is called.
- Update ContentEntityForm::buildEntity(): prevent it from resetting the revision_id (vid) if $node->in_preview is truthy.
This effectively causes the node entity reconstructed from the $form_state serialization to preserve the revision_id (vid).
Remaining tasks
- Determine if clearing revision_id (vid) is intentional in the node-in-preview flow.
- Review
User interface changes
None
API changes
A $node object build from a serialized $form_state will now have the revision_id (vid) set.
Data model changes
None?
Release notes snippet
Node Preview: a $node object build from a serialized $form_state will now have the revision_id (vid) set.
| Comment | File | Size | Author |
|---|---|---|---|
| #11 | modal-library-pager-preview-error-3332784-11.patch | 3.19 KB | jedihe |
| #2 | d.o - 3332784-2-repro.mp4 | 731.4 KB | jedihe |
Issue fork drupal-3332784
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
jedihe commentedAttaching repro video, 50 seconds.
Comment #3
jedihe commentedComment #4
jedihe commentedComment #5
jedihe commentedBug is also reproducible in Drupal 9.5.1 Umami.
Comment #8
robert-arias commentedComment #9
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Proposed solution should be written in the issue summary. Based on the last comment not sure if the solution should be expanded or follow up made.
With a bug a test case should be added to show the issue.
Comment #10
jedihe commentedThanks for the detailed explanation, @robert-arias!
I was able to find what exactly causes the revision_id to go missing when persisting $form_state into private tempstore; that $form_state data is then used to rebuild the entity used for the preview page, as well as to populate the edit form (once the user goes back to editing). The problem is at Drupal\Core\Entity\ContentEntityForm->buildEntity, where the $entity->setNewRevision() call causes the $form_state to not be able to get the revision_id (vid) when serialization happens in NodeForm::preview() (this seems to only occur during the 'submit' pass of FAPI, see call stack below).
Knowing this, I think @robert-arias proposed fix doesn't address the root-cause: the preview submission flow causes the serialized $form_state to miss the revision_id (vid) value, which then causes the preview $entity to be in an incomplete state. Additionally, if the media library widget wants to use the revision_id as part of the anti-tamper hash, we should better try to preserve it.
I'm attaching a patch with a new approach: prevent the $entity->setNewRevision() call for preview submissions, so that the revision_id is preserved when serializing $form_state. I've only done very minimal testing in Drupal 9.5.3, but I'm curious to see what the testbot has to say.
Finally, this is the call stack (Drupal 9.5.3) showing the exact spot where the problematic $entity->setNewRevision() call is performed.
Comment #11
jedihe commentedThe failed assert was introduced in #2890758: Block visibility node type not working on preview/revision routes. I tried finding some evidence there about this assert being intentional (else it may have been written just to match observed behavior). Given I couldn't find any direct evidence for that, let's see if just tweaking the assert to match the new behavior gets all tests to pass.
Comment #12
jedihe commentedLinking to question I posted in Slack #contribute, trying to find out for sure if it is intentional for the node-entity-in-preview to not have a revision_id (vid) set: https://drupal.slack.com/archives/C1BMUQ9U6/p1678307331705029
Comment #13
jedihe commentedThere is a separate bug that can make it difficult to review this one. Adding it to related list.
Comment #14
robert-arias commentedThanks for finding that, @jehide! I absolutely overlooked the `::submitForm` call before previewing the node.
I think your solution is the answer to this issue - I knew my fix didn't address the underlying issue, thankfully you found it. I don't think that vid going missing is an intended behavior.
Comment #15
jedihe commentedJust updated the MR with #11 (adding a missing docblock + a minor method name change).
Comment #16
jedihe commentedRemoving 'Needs tests', since just updating an existing test gets the MR to pass.
Removing 'Needs Review Queue Initiative', after updating the issue summary.
Comment #17
jedihe commentedOriginal fix was reverted, as per #14. Thanks @robert-arias! :)
Comment #18
smustgrave commentedNeeds Review Queue Initiative doesn't have to do with the issue summary.
Still think additional tests will be needed. Editing the existing tests just to pass I don't think covers the scenario of the bug. But will let the next reviewer decide.
Comment #19
jedihe commentedOops! apologies for the mistake :)
The question about writing a separate test for this is certainly relevant. Off the top of my head, I don't see a different way to test for this than what NodeBlockFunctionalTest.php does; AFAIK, Drupal core does not include a way to render the revision_id for a node entity, in the preview page. Let's see what other reviewers say :).
Comment #20
smustgrave commentedSeems no one else picked it up.
I tried replicating again for D10.1 following the steps in the issue summary and could not trigger an error.
Is there a step missing in the issue summary?
Comment #22
johnvComment #23
jedihe commentedThis is not reproducible anymore. Tried with 10.5.3 in simplytest.me, as well as 11.2.3. in an already built site.