Problem/Motivation
I can't seem to edit any fields for existing views. Steps to reproduce:
- Do a fresh install of HEAD (I am on 2219b31)
- Goto admin/structure/views/view/user_admin_people
- Click on anything in Fields to edit it.
- See the Views spinner briefly, then nothing.
The exception is the following ...
The website encountered an unexpected error. Please try again later.
LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\Core\Ajax\AjaxResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 145 of core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php).
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1)
Stack\StackedHttpKernel->handle(Object, 1, 1)
Drupal\Core\DrupalKernel->handle(Object)
I started this as a Major, but I really think this is a Critical, as it makes editing anything with Views unusable.
Proposed resolution
Update FieldPluginBase::buildOptionsForm() to use a proper render array, rather than hardcoded and rendered output.
Build the Views AJAX forms in a render context in order to ensure that cacheable metadata is bubbled up.
Update Views testing bases class to double check that corresponding AJAX paths for NOJS requests work properly.
Remaining tasks
None.
User interface changes
None.
API changes
None.
Data model changes
None.
Beta phase evaluation
Issue category | Bug because Views functionality is currently broken. |
---|---|
Issue priority | Critical because Views is essentially useless to the majority of site owners without being able to edit field output. |
Unfrozen changes | Unfrozen because it addresses a critical bug. |
Comment | File | Size | Author |
---|---|---|---|
#44 | 2527606-test-only.patch | 1022 bytes | catch |
#37 | interdiff.txt | 712 bytes | dawehner |
#37 | 2527606-37.patch | 5.08 KB | dawehner |
#37 | interdiff.txt | 665 bytes | dawehner |
#37 | 2527606-36.patch | 5.08 KB | dawehner |
Comments
Comment #1
mpdonadioComment #2
dawehnerThis is certainly a critical, given that the views UI is pretty much entirely broken!
Comment #3
dawehnerComment #4
dawehnerThis is the first problem I found.
Comment #5
plachManually tested and the patch fixes the issue. Settings to NW for missing tests.
Comment #6
plachWorking on test coverage
Comment #7
Wim LeersA bug/missing test coverage, uncovered thanks to #2450993: Rendered Cache Metadata created during the main controller request gets lost.
Comment #8
plachTest coverage
Comment #9
plachWithout useless cruft
Comment #10
dawehnerLet's do it right this time.
Comment #11
martin107 CreditAttribution: martin107 commenteds/see/seem
Comment #12
xjmWow... that's an impressive bug. Edit: And yeah, this is critical.
Comment #13
xjmComment #15
xjmAlso, +1 for the render array use replacing the
SafeMarkup::set()
call. It's actually reassuring that that is the fix and means our larger critical objectives are actually on the right track. :)Comment #16
catchAnything worth asserting other than the 200? Content type header maybe?
Otherwise looks great.
Comment #17
xjmThere was a crosspost that made the result reporting goofy for the test-only patch, but it does fail locally. I also managed to dig the result out of the testbot logs:
https://qa.drupal.org/pifr/test/1088358
Edit: I crossposted with catch; +1 for adding an additional assertion.
Comment #18
Wim LeersNit: unwanted space in
Comment #19
mpdonadioComment #20
mpdonadioJust repeating what @catch and @xjm said, but with a slightly different idea...
Given the severity of this bug, and the fact that we didn't have a test that caught it, is this addition sufficient? How about testing the non-JS path, checking for a 200, and then making sure the options form got rendered?
Comment #21
dawehnerHere is an idea, "hack"
drupalGet()
with nojs.Comment #22
larowlanHow much overhead does this add to every views UI test? Not saying I don't love the idea, but should it be opt-in rather than opt-out?
Also, should we document the extra 'no_ajax_check' option on this method instead of using
{@inheritdoc}
Also what happens if there is no 'ajax' in the $path, - we'd end up with a duplicate request to the same path right? because
str_replace($url, ...)
would be the same as the previous $url?Also I think I've used my quota of alsos.
Comment #23
dawehnerWell, here it is checking whether nojs is in there.
I think the additional request is worth the additional test coverage
Comment #24
larowlanWhoops, yeah I misunderstood, we're going the other way (nojs » ajax), ignore me - so I think we should just document the no_ajax_check option on the overridden method.
Comment #25
dawehnerGiven that the patch is green, I think its fine for now to just skip the option.
Comment #26
mpdonadioI'm confused. In HEAD, why does admin/structure/views/nojs/handler/user_admin_people/page_1/field/created work, but admin/structure/views/ajax/handler/user_admin_people/page_1/field/created throws a 500?
Is this because of #2450993: Rendered Cache Metadata created during the main controller request gets lost, that in the ajax callback FieldPluginBase::buildOptionsForm() is being called outside of a rendering context, while the from nojs callback it is in one? If that is the case, it seems like we should do a full test run on a side issue with the hunk in UITestBase moved to WebTestBase (well, that may get tricky) to see if there are any other hidden gotchas.
Comment #27
plachLooking at logs the test suite execution time does not seem to be heavily affected by the additional test coverage.
Aside form that, I agree with @mpdonadio that the fact that the error happens only in the AJAX context could use some additional investigation. However I think the suspect that something more might be wrong is not enough to hold off a critical issue, so I think a non-critical follow-up would be better for that.
My tiny test coverage patch was completely superseded by the new generic test coverage, so I think it's fine for me to RTBC this.
Comment #28
catchI opened #2528124: Additional simpletest and/or manual testing of Views UI for follow-up testing.
But I still think we should check content type header or something to ensure this is a valid response. I'm sure Drupal 8 was fataling with a 200 response at one point.
Comment #29
Fabianx CreditAttribution: Fabianx as a volunteer commentedThat is a total nit, but:
$output[]['#markup'] =
looks totally strange to my eyes ...
It creates a new element, then makes it empty, then adds #markup to it, then adds data to that.
What about:
$output[] = ['#markup' => ... ]
instead?
---
Overall except for catch' remark, RTBC + 1
Comment #30
Wim LeersRather than fixing this one case, of which there will likely be more in other Views plugins/handlers, I think it'd be better to update this code from:
to:
Comment #31
dawehnerYeah, there we go.
Comment #32
xjmInline comment would be super here.
NW for the additional test assertion (see @catch's comment above).
Comment #33
dawehnerSure, let's do that. I removed the test coverage from FieldUITest because the generic drupalGet() one covers that already, but much better.
Comment #34
Fabianx CreditAttribution: Fabianx for Drupal Association commentedThe render_context needs to be applied still to $form.
=> CNW
Comment #35
dawehner... this was a old comment
Comment #36
Wim LeersThe fact that we now wrap the form building in a render context means that all changes here are now technically no longer necessary, but they're still an improvement of course.
I'll leave it to a committer to decide whether to do the right, yet strictly speaking now unnecessary thing.
This does NOT render the form, it builds the form. This should probably mention that this specifically wants to allow Views handlers/plugins that provide forms to still do early rendering. If they didn't do early rendering, this would not be necessary.
Oh, nice, this is very comprehensive for sure :)
Comment #37
dawehnerI think fixing the UI with that is not a bad idea.
Comment #38
plachReviews above are addressed back to RTBC.
Patch to commit is #37 (https://www.drupal.org/files/issues/2527606-37.patch).
Comment #39
mpdonadioUpdated IS to match approach in #37.
Comment #40
Fabianx CreditAttribution: Fabianx for Drupal Association commentedRTBC + 1
Unrelated:
I will open a follow-up to add a $render_context->applyTo() method directly.
Edit: Opened #2528322: Add RenderContext::applyTo method
Comment #41
alexpottNice one less SafeMarkup::set() too! Committed c78d806 and pushed to 8.0.x. Thanks!
Comment #43
Wim LeersRTBC +1Too late :) Congrats!
Comment #44
catchI applied just the test changes, ran a couple of Views UI tests, nothing failed.
Here's a test-only patch. I'm wondering if we got the exception because we were in an AJAX response, and then we updated the tests to use non-AJAX, so now we're not testing it at all again.
So if this issue goes to CNW, it's RTBC. And if it stays at RTBC, it's CNW ;)
Comment #45
catchI don't think I applied the patch before running the tests locally, which obviously would not fail 'cos that's just HEAD. So ignore #44 but it's always nice to have test-only patches on issues for confidence.
Comment #46
alexpottI can confirm
Drupal\views_ui\Tests\FieldUITest
fails with #44 applied.Comment #48
alexpottThe revert and re-commit added @catch to the list of people credited.
Comment #49
Wim LeersInteresting how the re-commit showed up before the revert. That really confused me :)