Body: <p>I'm working on a Cloudflare integration plugin for Craft 3. I set up the plugin with settings, which works fine so far. Now I intended to verify the Cloudflare credentials using an AJAX call.  </p>
  
  <p>I set up a controller at <code>controllers/DefaultController</code> with a method named <code>actionFetchZones</code>:</p>
  
  <pre><code>class DefaultController extends Controller {
      protected $allowAnonymous = [ 'fetch-zones' ];
  
      public function init() {
          parent::init();
          $this-&gt;defaultAction = 'fetch-zones';
      }
  
      public function actionFetchZones() {
          return $this-&gt;asJson( Plugin::getInstance()-&gt;cloudflare-&gt;getZones() );
      }
  }
  </code></pre>
  
  <p>I registered the action in the plugin class:</p>
  
  <pre><code>// register the actions
  Event::on(
      UrlManager::class,
      UrlManager::EVENT_REGISTER_CP_URL_RULES,
      function( RegisterUrlRulesEvent $event ) {
          $event-&gt;rules['POST cloudflare/zones'] = 'cloudflare/fetch-zones';
      }
  );
  </code></pre>
  
  <p>But the response is </p>
  
  <pre><code>POST https://host.tld/admin/actions/cloudflare/zones 404 (Not Found)
  </code></pre>
  
  <p>When I request <code>/admin/actions/cloudflare</code> instead, I receive a <code>200</code> response.</p>
  
  <p>The plugin handle is set to <code>cloudflare</code>, the app works fine otherwise. What am I doing wrong?</p>
  
  <p><strong>Edit:</strong> As requested, below is the AJAX call:</p>
  
  <pre><code>Craft.postActionRequest(
    'cloudflare/zones',
    { apiKey, email },
    (response, textStatus, request) =&gt; { /* ... */ }
  );
  </code></pre>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-07T18:12:31.620Z
Comments.Text: The most important part is missing... The ajax request. Did you define your routes snake-case and include a csrf token in your request? I'm not sure if you can leave the controller name blank if you name it default just a guess but what happens when you do `cloudflare/default/fetch-zones`
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-08T06:08:50.117Z
Comments.Text: @RobinSchambach I added the AJAX call, nothing too special though. I supposed the CSRF would get included by `Craft.postActionRequest`?
Comments.UserDisplayName: Moritz Friedrich
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-08T06:15:01.303Z
Comments.Text: Not sure. You can see it in your browser console network tab. Or I can try it for you in about 1.5h. Since I always use angular I have to include it on my own. Or you can deactivate the token in your config. If it works afterwards you know what you have to do
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-08T07:23:54.143Z
Comments.Text: Ok I tested it. `Craft.postActionRequest` sends the CSRF token. When I copy your code it does not work either for me, but when I do `Craft.postActionRequest('cloudflare/default/fetch-zones'.....` everything is fine
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-08T07:31:45.633Z
Comments.Text: I'm on my way into the office, will test and get back to you ASAP :)
Comments.UserDisplayName: Moritz Friedrich
Tags: <craft3><controller>
Title: Craft 3 Plugin - Only default action works
ThreadText: # Craft 3 Plugin - Only default action works
  
  (Asked by: username_0 on 2017-12-07)
  
  I'm working on a Cloudflare integration plugin for Craft 3. I set up the plugin with settings, which works fine so far. Now I intended to verify the Cloudflare credentials using an AJAX call.
  
  I set up a controller at `controllers/DefaultController` with a method named `actionFetchZones`:
  
  ```
  class DefaultController extends Controller {
      protected $allowAnonymous = [ 'fetch-zones' ];
  
      public function init() {
          parent::init();
          $this->defaultAction = 'fetch-zones';
      }
  
      public function actionFetchZones() {
          return $this->asJson( Plugin::getInstance()->cloudflare->getZones() );
      }
  }
  
  ```
  
  I registered the action in the plugin class:
  
  ```
  // register the actions
  Event::on(
      UrlManager::class,
      UrlManager::EVENT_REGISTER_CP_URL_RULES,
      function( RegisterUrlRulesEvent $event ) {
          $event->rules['POST cloudflare/zones'] = 'cloudflare/fetch-zones';
      }
  );
  
  ```
  
  But the response is
  
  ```
  POST https://host.tld/admin/actions/cloudflare/zones 404 (Not Found)
  
  ```
  
  When I request `/admin/actions/cloudflare` instead, I receive a `200` response.
  
  The plugin handle is set to `cloudflare`, the app works fine otherwise. What am I doing wrong?
  
  **Edit:** As requested, below is the AJAX call:
  
  ```
  Craft.postActionRequest(
    'cloudflare/zones',
    { apiKey, email },
    (response, textStatus, request) => { /* ... */ }
  );
  
  ```
  
  **Tags:** craft3, controller
  
  > **Comments:**
  > **username_1**: The most important part is missing... The ajax request. Did you define your routes snake-case and include a csrf token in your request? I'm not sure if you can leave the controller name blank if you name it default just a guess but what happens when you do `cloudflare/default/fetch-zones`  
  > **username_0**: @username_1 I added the AJAX call, nothing too special though. I supposed the CSRF would get included by `Craft.postActionRequest`?  
  > **username_1**: Not sure. You can see it in your browser console network tab. Or I can try it for you in about 1.5h. Since I always use angular I have to include it on my own. Or you can deactivate the token in your config. If it works afterwards you know what you have to do  
  > **username_1**: Ok I tested it. `Craft.postActionRequest` sends the CSRF token. When I copy your code it does not work either for me, but when I do `Craft.postActionRequest('cloudflare/default/fetch-zones'.....` everything is fine  
  > **username_0**: I'm on my way into the office, will test and get back to you ASAP :)  
  
  ---
  
  ## 0 answers
  
  