1

As mentioned in the subject I'm getting a MethodNotAllowedHttpException in RouteCollection.php when trying to submit a form using jQuery and ajax

I've tried the following in my routes.php file

Route::post('/send/', 'CommsController@send');

and

Route::patch('/send/', 'CommsController@send');

Controller

use App\Http\Controllers\Controller;

class CommsController extends Controller
{
    protected function send(Request $request);
    {
        return response($request);
    }
}

jQuery ajax

if ( isValid ) {
    $( ".validation-summary" ).html( "Sending message..." );

    var data = "";

    data = "message_type=contact"
        + "&first_name=" + first_name.val()
        + "&last_name=" + last_name.val()
        + "&email=" + email.val()
        + "&message=" + message.val()

    $.ajax({
        type: "post",
        url: "send",
        data: data,
        error: function( response ) {
            $( ".validation-summary" ).removeClass( "success" );
            $( ".validation-summary" ).addClass( "validation-summary error" );
            $( ".validation-summary" ).html( "Error" );
        },
        success: function() {
            $( ".validation-summary" ).html( "Message sent." );
        }               
    });
    return false;
} else {
    return false;
}

Thanks.

Tim Kruger
  • 863
  • 2
  • 10
  • 26
  • Using the network tab of your browsers developer tools can you confirm that it is definitely getting sent to the correct end point with the correct HTTP method? – Rwd Jan 14 '16 at 09:28
  • I'm getting a 405 (Method Not Allowed) exception, if the routes.php is patch and 500 if it's set to post. Not too sure why though. – Tim Kruger Jan 14 '16 at 10:41
  • What does your php_error.log say? – Rwd Jan 14 '16 at 12:40
  • Thanks didn't even think about checking the php_error.log file. The log entry that's probably of most importance says local.ERROR: Illuminate\Session\TokenMismatchException in VerifyCsrfToken.php:67, so I added {!! csrf_field() !!} to my form but it still throws the same error. – Tim Kruger Jan 14 '16 at 12:57

5 Answers5

1

In Laravel 5.2, you need to set the route in web middleware and I presume that you have already placed the post route inside the middleware:

Route::group(['middleware' => ['web']], function() {

    Route::post('/send', 'YourController@methodName');

});

If I were at your place, I would have done something else though similar to what your code is doing.

jQuery

(function() {
    // replace $('.btnSubmit') with whatever you want
    $('.btnSubmit').click(function(e) {
        var form       = $('#yourFormId'),
            postAction = form.attr('action'),
            postData   = form.serialize();

        $.ajax({
            type: 'POST',
            url: postAction,
            data: postData,
            success: function(res) {
                console.log(res);
            },
            error: function(res) {
                console.log('Error:' + res);
            }
        });

        return false;
    });
})();

What I did:

  1. Placed the action parameter directly in the form, instead of defining it in jQuery AJAX
  2. Serialize the input values of the form and posted the same
  3. Used Self Invoking Anonymous Function

Just a side note:

You are repeating $('.validation-summary') for 5 times. This means that you are violating the Principles of DRY which is not recommended. Solution for this:

var valSum = $('.validation-summary');

And then in you can use it n number of times in that piece of code.

Hope this helps you out. Happy Coding. Cheers.

Saiyan Prince
  • 3,930
  • 4
  • 28
  • 71
  • 1
    Hi @user3514160 yeah I have set the route in the web middlewhare, will change my code to resemble your snipped above and see if that sorts the problem out. Thanks for the side note, I'll make that change as well, a much better option. – Tim Kruger Jan 14 '16 at 10:34
  • 1
    Oh by the way going forward I should probably use .done and .fail instead of success and fail. – Tim Kruger Jan 14 '16 at 11:06
  • 1
    I guess, both the methods will end up doing the same thing – Saiyan Prince Jan 14 '16 at 11:06
  • 2
    Yeah but according to this post http://stackoverflow.com/questions/10931836/should-i-use-done-and-fail-for-new-jquery-ajax-code-instead-of-success-and I think success and error are suppose to be deprecated, although I'm using jquery-2.1.4.js and I can still use success and error. – Tim Kruger Jan 14 '16 at 11:21
  • 1
    Okay.. Then go with `.done()-` and `.fail()` method. I was not knowing that they will be deprecated. Thanks for the link. :) – Saiyan Prince Jan 14 '16 at 11:24
  • 1
    No problem, thought you might not be aware hence the link. – Tim Kruger Jan 14 '16 at 11:35
  • 1
    Yeah! Once you solve the issue, kindly add your own answer and then accept the same.. :) – Saiyan Prince Jan 14 '16 at 11:36
  • 1
    Cool no problem, I'll do that. – Tim Kruger Jan 14 '16 at 12:47
1

Try 'POST' instead of 'post' in your routes.php and your ajax call. Had same problem with that, and this fix it for me. Hope it helps.

MasterSith
  • 175
  • 6
  • Hi @MasterSith, I might be mistaken but I don't think you need to change 'post' to 'POST' in the routes.php, but you're probably right in saying I should change in in my ajax call. This wasn't the problem though, but thanks very much for your help. – Tim Kruger Jan 14 '16 at 10:30
1

As per your last comment about the csrf_token the best solution (IMO) is:

Add the following line to inside <head></head>:

<meta id="csrf_token" name="csrf_token" content="{{ csrf_token() }}">

and then add the following js:

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content')
    }
});

This will mean that the csrf is always included in your ajax calls automatically.


Alternatively, you can just get the value for _token and include it in your data variable like so:

data = "message_type=contact"
    + "&first_name=" + first_name.val()
    + "&last_name=" + last_name.val()
    + "&email=" + email.val()
    + "&message=" + message.val()
    + "&_token=" + $("input[name=_token]").val();

Hope this helps!

Rwd
  • 34,180
  • 6
  • 64
  • 78
  • Hi @Ross Wilson I actually already did that just before your post, but my $ajax.done function still doesn't get called and the statusText of my $ajax.fail function returns 'OK', WTF why does it return 'OK' on fail. Anyways I'm going to kill my lungs and will post my updated code in a bit. Thanks for all your help though, I appreciate it. – Tim Kruger Jan 14 '16 at 13:32
1

UPDATED: my routes.php file

Route::post('/send', 'CommsController@send');

Controller

public function send(Request $request)
{
    // return view('contact.contact');
    return view('contact.contact')->with('data', json_encode($request));
}

app/Http/Middleware/VerifyCsrfToken.php // This addition to the VerifyCsrfToken.php might not be necessary, not too sure though

protected function tokensMatch($request) {
    // If request is an ajax request, then check to see if token matches token provider in
    // the header. This way, we can use CSRF protection in ajax requests also.
    $token = $request->ajax() ? $request->header('X-CSRF-Token') : $request->input('_token');

    return $request->session()->token() == $token;
}

jQuery ajax

<head>
    <meta id="csrf_token" name="csrf_token" content="{{ csrf_token() }}">
</head>

$( document ).ready(function() {
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });

    ....

    $.ajax({
        type: "POST",
        url: postAction,
        data: JSON.stringify(postData),
        dataType: 'json',
        encode: true
    }).done(function(response) {
        // log data to the console so we can see
        console.log(response); 

        // here we will handle errors and validation messages
        if ( ! response.success ) {
            valSum.removeClass( "success" );
            valSum.addClass( "validation-summary error" );
            valSum.html( response.errors );
        } else {
            // $( ".validation-summary" ).html( "Message sent." );
            valSum.html( response.message );
        }
    })
    .fail(function(response) {
        valSum.removeClass( "success" );
        valSum.addClass( "validation-summary error" );
        valSum.html( "Server Error: " + response.statusText + " processing your request, please contact Dorothea or report a bug." );
    });

Network error been returned in my browser

500 (Internal Server Error)

php_error.log file entry

local.ERROR: Illuminate\Session\TokenMismatchException in C:\cx\laravel\dorothea\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php:67
Tim Kruger
  • 863
  • 2
  • 10
  • 26
1

Hi @user3514160 I just wanted to let you know that I solved my problem by changing the post method to get methods. Not too sure why get is working but post isn't but for now at least the issue has been resolved.

If anyone can shed some light as to why this would be the case that would be great.

Tim Kruger
  • 863
  • 2
  • 10
  • 26