Steps to reproduce:

  1. Enable the "REST" and "Serialization" module
  2. Create a view without block and page, but add a "REST export". Give the view a path and save it.
  3. Now, a lot of forms will not submit. For instance edit the body field of the article content type ( admin/structure/types/manage/article/fields/node.article.body/field ). Change the "Allowed number of values" to limited and try to save. It will result in the "Method Not Allowed" error. If you disable the view and try to edit the same field setting it will work.

I'm not sure if the problem is from views, rest, or even another component.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

idflood’s picture

Component: views.module » rest.module

After looking at some code I'm still not sure where the problem is but it may be more related to the rest module than views.

edit: It seems to be related to the requirements defined in rest/lib/Drupal/rest/Plugin/views/display/RestExport.php->collectRoutes.

idflood’s picture

Status: Active » Needs review
FileSize
1.21 KB

Here is a first patch. Not sure if this really works but at least it doesn't give the error on forms.

idflood’s picture

Title: "Method Not Allowed" on most admin forms after creating a "REST export" view. » REST export view add requirement to all paths, leading to "Method Not Allowed" on most forms
klausi’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Interesting, this totally makes sense, thanks for catching this. Of course we should not modify all routes, but only our own.

Patch looks good, but this needs a test case. I think we can just unit-test collectRoutes() and check that it only modifies its own routes that are passed in a collection.

idflood’s picture

Status: Needs work » Needs review
FileSize
1.71 KB

I've started to work on a test. But it is not really executed, any idea why ? (0 pass, 0 fail, ... no test result to display)

edit: there was a little syntax error but even with it corrected it doesn't execute the test. (I was using [] instead of array() )

The last submitted patch, method_not_allowed-2065949-5-test-not-working.patch, failed testing.

idflood’s picture

Same patch as #5 but with the typo corrected. The patch is still not really executed (no test result to display).

klausi’s picture

  1. +++ b/core/modules/rest/lib/Drupal/rest/Tests/Views/CollectRoutesTest.php
    @@ -0,0 +1,50 @@
    +/**
    + * Defines tests for collectRoutes.
    + */
    

    Should be "... for the collectRoutes() method."

  2. +++ b/core/modules/rest/lib/Drupal/rest/Tests/Views/CollectRoutesTest.php
    @@ -0,0 +1,50 @@
    +
    +  function setUp() {
    

    Scope modifier missing, I think it is protected.

  3. +++ b/core/modules/rest/lib/Drupal/rest/Tests/Views/CollectRoutesTest.php
    @@ -0,0 +1,50 @@
    +    $this->rest_export = RestExport::create($container, array(), "test_routes", array());
    +    $this->routes = new RouteCollection();
    +    $this->routes->add('test_1', '/test/1');
    +    $this->routes->add('test_2', '/test/2');
    

    All class properties should be defined explicitly.

    And shouldn't you test the requirements of one valid route that belongs to the plugin and should be modified?

idflood’s picture

Thanks for the review, I've updated the test.

And shouldn't you test the requirements of one valid route that belongs to the plugin and should be modified?

I haven't fixed this since I have no idea of how it can be done.

I changed the test location and took example on the views module for the test on the advice of berdir. The test still doesn't work, but when executed from the command line it gives an interesting error.

1) Drupal\rest\Tests\CollectRoutesTest::testRoutesRequirements
Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The service definition "content_negotiation" does not exist.
...

The command: cd core; ./vendor/bin/phpunit --filter=CollectRoutesTest

Status: Needs review » Needs work

The last submitted patch, method_not_allowed-2065949-9-test-not-working.patch, failed testing.

larowlan’s picture

kicked this along some more, but stuck on


There was 1 error:

1) Drupal\rest\Tests\CollectRoutesTest::testRoutesRequirements
Argument 1 passed to Mock_Serializer_b424d9d2::init() must be an instance of Drupal\views\ViewExecutable, instance of Mock_ViewExecutable_038f176a given, called in /var/www/d8/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php on line 849 and defined

/var/www/d8/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php:849
/var/www/d8/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php:257
/var/www/d8/core/modules/rest/tests/Drupal/rest/Tests/CollectRoutesTest.php:159
/usr/share/php/PHPUnit/TextUI/Command.php:176
/usr/share/php/PHPUnit/TextUI/Command.php:129

larowlan’s picture

Sorry, that was the interdiff.
Full test and interdiff

larowlan’s picture

Priority: Normal » Major

this is at least major, if not critical

larowlan’s picture

Status: Needs work » Needs review
FileSize
6.13 KB
4.86 KB

view != views - fixed

So we should have red/green here.

larowlan’s picture

Priority: Major » Critical

Given that once any view of this type is added, any non GET request returns a Method Not Allowed

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests

This makes a lot more sense when you view the patch without whitespace changes:

diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php b/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php
index 33a7e6b..4f7a77f 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php
@@ -253,7 +253,10 @@ public function optionsSummary(&$categories, &$options) {
    */
   public function collectRoutes(RouteCollection $collection) {
     parent::collectRoutes($collection);
+    $view_id = $this->view->storage->id();
+    $display_id = $this->display['id'];
 
+    if ($route = $collection->get("view.$view_id.$display_id")) {
     $style_plugin = $this->getPlugin('style');
     // REST exports should only respond to get methods.
     $requirements = array('_method' => 'GET');
@@ -261,8 +264,7 @@ public function collectRoutes(RouteCollection $collection) {
     // Format as a string using pipes as a delimeter.
     $requirements['_format'] = implode('|', $style_plugin->getFormats());
 
-    // Add the new requirements to each route.
-    foreach ($collection as $route) {
+      // Add the new requirements to the route.
       $route->addRequirements($requirements);
     }
   }

Running the test without the fix, it has 1 error:

1) Drupal\rest\Tests\CollectRoutesTest::testRoutesRequirements
First route has no requirement.
Failed asserting that 0 matches expected 2.

Looks good to me, nice work.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Looks good to me. Committed/pushed to 8.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.