Search code examples
jqueryajaxlaravellaravel-5x-editable

Inline editing with Laravel 5 and Bootstrap Editable: 405 Method Not Allowed


I have a comment form and list on each post in my app, I just imported Bootstrap Editable to be able to give the users access to edit their comments inline without page reload.

But I keep getting this error

MethodNotAllowedHttpException in RouteCollection.php line 219:

POST http://localhost/r2/public/posts/comment/update 405 (Method Not Allowed)

I'm assuming it's something to do with my comment routes but I can't figure out what.

EDIT: After adding type: 'post' to ajaxOptions I started getting a different error

Creating default object from empty value

It seems like Input::get('commenter_comment') is not returning anything. I guess this is wrong anyway as this is not the X-Editable field that is appearing.

How can I grab the X-Editable field?

Routes

Route::get('{post}/comment', ['as' => 'comment', 'uses' => 'CommentController@index']);
Route::post('{post}/post_this_comment', 'CommentController@post_this_comment');
Route::get('{post}/recaptcha', 'CommentController@recaptcha');
Route::get('{post}/reply_comment', 'CommentController@reply_comment');
Route::post('{post}/per_page', 'CommentController@per_page');
Route::post('{post}/comment/update', 'CommentController@update');

Update() method in CommentController

public function update() {
    $commentId = Input::get('pk');

    $newComment = Input::get('commenter_comment');

    $commentData = Comment::whereId($commentId)->first();

    $commentData->comment = $newComment;

    if($commentData->save())
        return Response::json(array('status'=>1));
    else
        return Response::json(array('status'=>0));
}

The View

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

            $('.testedit').editable({
                validate: function(value) {
                    if($.trim(value) == '')
                        return 'Value is required.';
                },
                type: 'textarea',
                url: 'comment',
                title: 'Edit Comment',
                placement: 'top',
                send:'always',
                ajaxOptions: {
                    dataType: 'json'
                }
            });
        }
    );
</script>

<p><a href="#" class="testedit" pk="{{ $each_comment->id }}">{!! $each_comment->comment !!}</a></p>

Solution

  • As I mentioned, MethodNotAllowedHttpException is thrown when you are using different HTTP verb. I mean, in you routes you declare the update route with post verb:

    Route::post('{post}/comment/update', 'CommentController@update');
    

    However, in you ajax options when type is not defined it do the request in GET, so you must to define it:

    ajaxOptions: type: 'post'
    

    Now, another error comes. You are not passing the post id expected in route's definition, that's why you are receiving an empty id, in consequence, a empty object is returned from database. So, you must to pass it as. But first, lets change the markup a little bit for each comment in order to set the the post's url via data-url and pk via data-pk attributes:

    <a 
    href="#" 
    class="testedit" 
    data-pk="{{ $each_comment->id }}"
    data-url="{!! url($post->id . '/comment/update') !!}">
        {!! $each_comment->comment !!}
    </a>
    

    Now, x-editable will catch the url and pk values automatically without be set explicitly. Your final code should be close like this:

    $(document).ready(
            function(){
                $.ajaxSetup({
                    headers: {
                        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                    }
                });
    
                $('.testedit').editable({
                    validate: function(value) {
                        if($.trim(value) == '')
                            return 'Value is required.';
                    },
                    type: 'textarea',
                    title: 'Edit Comment',
                    placement: 'top',
                    send:'always',
                    ajaxOptions: {
                        dataType: 'json',
                        type: 'post'
                    }
                });
            }
        );
    

    Don't forget that every argument defined in routes could be injected in controller's function. For example, your route is defining a {post} that expected to be the post id to edit:

    Route::post('{post}/comment/update', 'CommentController@update'); 
    

    So, in your update() just inject the argument:

    public function update(Request $request, $post) {
        //$post has the Id of post to be edited
    
        // catching pk id:
        $pk = $request->get('pk');
    
        // catching the new comment
        $comment = $request->get('value');