2

Hello people I am facing a problem with my comments system in laravel and ajax. Actually it works only with php but i'm having problems with ajax.

This is the error message:

Status Code:500 Internal Server Error. And the error says: 1/3 SQLSTATE[23000]:Integrity constraint violation:1048 Column 'post_id' cannot be null.

I am editing the comments in a modal, I can create a new comment but the problem is editing it with ajax.

JS code:

<script>

  var commentId = 0;
        var divcomment = null;

        $('.edit-comment').click(function(event){
          event.preventDefault();
          var divcomment = this.parentNode.parentNode;
          commentId = $("#comment-post", event.target.parentNode.parentNode).data('commentid');
          var commentBody = $(divcomment).find('#display-comment').text();
          $('#comment').val(commentBody);
          $('#edit-comment').modal();
        });

        $('#modal-save').click(function(){
            $.ajax({
                method: 'POST',
                url: urlEdit,
                data: {
                    comment: $('#comment').val(),
                    commentId: commentId,
                    _token: token,
                    _method: 'POST'
                 }
            })
            .done(function (msg){
                $(divcomment).text(msg['new_comment']);
                $('#edit-comment').modal('hide');
            });
        });

</script>

Here's the HTML:

<article class="row">
    <div class="col-md-3 col-sm-3 hidden-xs">
        <figure class="thumbnail">
            <img class="img-responsive" src="/uploads/avatars/{{ $comment->user->profilepic  }}" />
            <figcaption class="text-center">{{ $comment->user->name }}</figcaption>
        </figure>
    </div>
    <div class="col-md-8 col-sm-8">
        <div class="panel panel-default arrow left">
            <div class="panel-body">
                <header class="text-left">
                    <div class="comment-user"><i class="fa fa-user"></i> {{ $comment->user->name }}</div>
                    <time class="comment-date" datetime="{{ $comment->created_at->diffForHumans() }}"><i class="fa fa-clock-o"></i> {{ $comment->created_at->diffForHumans() }}</time>
                </header>
                <div id="comment-post" data-commentid="{{ $comment->id }}">
                    <p id="display-comment">{{ $comment->comment }}</p>
                </div>
            </div>

            <div class="panel-footer list-inline comment-footer">
                @if(Auth::guest())

                    No puedes responder ningún comentario si no has ingresado.

                @else

                    @if(Auth::user() == $comment->user)
                        <a href="#" data-toggle="modal" data-target="edit-comment" class="edit-comment">Editar</a> <a href="#" data-toggle="modal" data-target="delete-comment" class="delete-comment">Eliminar</a>
                    @endif

                    @if(Auth::user() != $comment->user)
                        <a href="#">Responder</a>
                    @endif

                @endif
            </div>

        </div>
    </div>
</article>

My Edit Modal:

<div class="modal fade" id="edit-comment" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" style="color:#000;">Editar Comentario</h4>
      </div>
      <div class="modal-body">
        <form>
          <div class="form-group">
            <label for="comment">Editar comentario</label>
            <textarea class="form-control" name="comment" id="comment"></textarea>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn-comment-dismiss btn-comment-modal" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Cerrar</button>
        <button type="button" class="btn-comment-edit btn-comment-modal" id="modal-save"><span class="glyphicon glyphicon-ok"></span> Editar</button>
      </div>
    </div>
  </div>
</div>

My comments update route:

Route::POST('comments/', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);

My update function on CommentsController:

public function update(Request $request)
{

    $this->validate($request, [
        'comment' => 'required'
    ]);

    $comment = Comment::find($request['commentId']);
    if (Auth::user() != $comment->user) {
        return redirect()->back();
    }

    $comment->comment = $request['comment'];

    $comment->update();
    return response()->json(['new_comment' => $comment->comment], 200);

}

And finally the variables created on my Post single view "where i display the comments"

<script>

  var token = '{{ Session::token() }}';
  var urlEdit = '{{ url('comments/update') }}';

</script>

UPDATE:

Comments table scheme:

    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id');
            $table->text('comment');            
            $table->boolean('approved');
            $table->integer('post_id')->unsigned();
            $table->timestamps();
        });

        Schema::table('comments', function ($table){
            $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
        });
    }

New Update:

Errors Messages:

Error 1/3

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'post_id' cannot be null

Error 2/3

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'post_id' cannot be null

Error 3/3

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'post_id' cannot be null (SQL: insert into comments (comment, approved, post_id, user_id, updated_at, created_at) values (Another yet comment, 1, , 4, 2017-06-04 04:54:34, 2017-06-04 04:54:34))

Additional Info:

General

Request URL:http://devmedia.dev/comments/update
Request Method:POST
Status Code:500 Internal Server Error
Remote Address:127.0.0.1:80
Referrer Policy:no-referrer-when-downgrade

Form

comment:Another yet comment
commentId:13
_token:Do1gqYfziHij1nAj2CFOWwgdt7UWuubqbawrD5uX
_method:POST

Whole comments routes:

Route::post('comments/{post_id}', ['uses' => 'CommentsController@store', 'as' => 'comments.store']);
Route::get('comments/{id}/edit', ['uses' => 'CommentsController@edit', 'as' => 'comments.edit']);
Route::POST('comments/', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);
Route::delete('comments/{id}', ['uses' => 'CommentsController@destroy', 'as' => 'comments.destroy']);
Route::get('comments/{id}/delete', ['uses' => 'CommentsController@delete', 'as' => 'comments.delete']);
Daedalus
  • 7,586
  • 5
  • 36
  • 61
Juan Rincón
  • 307
  • 5
  • 15
  • Try using `save()` instead of `update()` to update the model. – Daedalus Jun 04 '17 at 05:10
  • Please attach schema of comments table. – kopaty4 Jun 04 '17 at 05:11
  • Hello @Anton look the update above in question – Juan Rincón Jun 04 '17 at 05:20
  • 2
    @JuanRincón I noticed that the address of your route is just `comments/`, while you are making a request for `comments/update`. Is this a typo, or is it possible that the wrong code is being executed? – kopaty4 Jun 04 '17 at 05:24
  • actually the route comments/ uses CommentsController@update as comments/update. so comments/update is the route – Juan Rincón Jun 04 '17 at 05:33
  • @JuanRincón the comment you are editing, has a 'post_id'? before the update. – Alan Torres Jun 04 '17 at 05:36
  • I did this in my models. Post model has many comments, and Comments model has many posts – Juan Rincón Jun 04 '17 at 05:45
  • 1
    I suggested `save()` instead of `update()` as `update()` usually takes a parameter; an array of fields to set to a value. I have yet to see it used otherwise, but I could be wrong. – Daedalus Jun 04 '17 at 06:25
  • @Daedalus already done with save and i get the same result – Juan Rincón Jun 04 '17 at 07:35
  • @JuanRincón Do you have access to your database? Also; the error given says `1/3`, which implies there are two more errors you have not posted. Please post them. – Daedalus Jun 04 '17 at 07:38
  • @JuanRincón As to the database access; since you know the comment Id; look up the comment in your database(if you have phpmyadmin access, or whatever ui you have for it(including a cli)), and check that it has a post_id value. – Daedalus Jun 04 '17 at 07:45
  • @Daedalus yes, every comment have a post id, in this case the only post who have comments is the post 9 "post_id = 9" about the erros 1/3 are the same, the last one "3" say the same but includes "insert into comment etc" and saying that it can't insert into post id, or can't find it "or access". Above in the question i added an update with the comments table scheme. The post id is a foreign key – Juan Rincón Jun 04 '17 at 08:25
  • @JuanRincón Dump your `$comment` variable after you create it; ensure that it has the `post_id` property. – Daedalus Jun 04 '17 at 08:27
  • @JuanRincón Also, please post the errors as they appear; do not try to summarize them; they may hold clues as to why this isn't working. – Daedalus Jun 04 '17 at 08:31
  • `code #attributes: array:7 [▼ "comment" => "Another yet comment" "approved" => true "post_id" => 9 "user_id" => 4 "updated_at" => "2017-06-04 04:32:51" "created_at" => "2017-06-04 04:32:51" "id" => 13 ]` – Juan Rincón Jun 04 '17 at 08:33
  • @JuanRincón Please add the rest of the errors to the question, as requested. Make sure to scrub any identifying information, such as passwords or hostnames. – Daedalus Jun 04 '17 at 08:50
  • @JuanRincón The stack snippet feature is for html/javascript/css code, not for general errors. I am thus fixing it now, but please remember for the future. – Daedalus Jun 04 '17 at 09:06
  • Question updated, one more thing, Laravel uses the form::model to update something.. of course route is needed. And about the post_id, i did the dump on the store function, i'm able to create new comments "without JS" – Juan Rincón Jun 04 '17 at 09:09
  • @JuanRincón Okay; now I know you already answered this above, but I need to make sure we're looking at the correct code here; your Route. Is it exactly `Route::POST('comments/'...`, or is there an `update` after the slash? – Daedalus Jun 04 '17 at 09:13
  • @JuanRincón I ask as error **#3** suggests that another controller method may be getting called; eg, the one to save a new comment, rather than update an existing comment, since the error points to an insert query rather than an update query. To that end, I'd like to see the rest of your comment-related routes added to the question, please. – Daedalus Jun 04 '17 at 09:16
  • Is a resource controller, so originally it was `code Route::put('comments/{id}', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);` but now that i'm using it with js i changed to the one posted above – Juan Rincón Jun 04 '17 at 09:19
  • @JuanRincón Please update your route(the one above) to add `update` after the slash, so it looks like this: `Route::POST('comments/update', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);`. My current hunch is the incomplete route is causing the bug. Also, I'm not entirely sure that `POST` is meant to be in all caps, as I don't know the IoC container well enough to see how casing in facades is handled. – Daedalus Jun 04 '17 at 09:20
  • let me add the whole comments routes – Juan Rincón Jun 04 '17 at 09:32
  • @JuanRincón Please change your route as I noted; if I am correct I will undelete my answer. I'd also recommend making `POST` into `post`. – Daedalus Jun 04 '17 at 09:40
  • @Daedalus The same.. i think i need to call the post_id maybe from the controller, look at this, this is the code i was using on "update function" before using js: `code $comment = Comment::find($id); $this->validate($request, array('comment' => 'required')); $comment->comment = $request->comment; $comment->save(); Session::flash('El comentario ha sido editado'); return redirect()->route('posts.show', $comment->post->id);` at the end the return redirect()->route('posts.show', $comment->post->id); – Juan Rincón Jun 04 '17 at 09:48
  • @JuanRincón Well I am right; just did some testing on my end; it is conflicting routes. Try putting your `comments.update` route above your `comments.store` route. Of course, you could also require that your `comments.store` route's post_id parameter is an integer. – Daedalus Jun 04 '17 at 09:49
  • @Daedalus and now, i'm trying to edit the comments as i did before and it gives me an error: MethodNotAllowedInHttpExcepion, in other words "post method not allowed" `code at RouteCollection->methodNotAllowed(array('POST', 'DELETE'))` – Juan Rincón Jun 04 '17 at 09:54
  • Ok is done and is working!! but now i have a problem =P i need to refresh the page to see the comments edited. – Juan Rincón Jun 04 '17 at 09:59
  • @JuanRincón I've posted the revised answer. Besides that point, you can see this SO answer for that question: https://stackoverflow.com/a/3715123/785241 – Daedalus Jun 04 '17 at 10:03
  • i can't make it refresh, i mean, not the whole page but the edited comment only – Juan Rincón Jun 04 '17 at 11:12
  • @JuanRincón Just change the text of your comment again, just like how you got it in the first place: `$(divcomment).find('#display-comment').text(comment)`, but in your ajax success function. – Daedalus Jun 04 '17 at 19:16
  • @Daedalus let me see if i got you, i will replace this on my main js file? – Juan Rincón Jun 05 '17 at 01:21
  • @JuanRincón In your `.done()` function, which is off of the ajax function, you can put the above line to update the comment. – Daedalus Jun 05 '17 at 01:23
  • I replaced on my .done function and works but to display the edited message i need to refresh manually the page, what i'm looking now is to load just the edited message and not the whole page. – Juan Rincón Jun 05 '17 at 04:11

1 Answers1

3

It appears my(and Anton's) hunch was correct. You have two conflicting routes.

Route::post('comments/{post_id}', ['uses' => 'CommentsController@store', 'as' => 'comments.store']);

And of course

Route::post('comments/', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);

Because the two routes use roughly the same route, laravel just goes by which is defined first, which is your comments.store route.

There are a couple ways to fix this.

  1. Change the order of your routes:

    Route::post('comments/update', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);
    Route::post('comments/{post_id}', ['uses' => 'CommentsController@store', 'as' => 'comments.store']);
    Route::get('comments/{id}/edit', ['uses' => 'CommentsController@edit', 'as' => 'comments.edit']);
    
  2. Use route constraints:

    Route::post('comments/{post_id}', [
        'uses' => 'CommentsController@store',
         'as' => 'comments.store'
    ])->where(['post_id' => '[0-9]+']);;
    Route::get('comments/{id}/edit', ['uses' => 'CommentsController@edit', 'as' => 'comments.edit']);
    Route::post('comments/update', ['uses' => 'CommentsController@update', 'as' => 'comments.update']);
    

Of note, I don't know how the Facade registrar handles the casing(lower, upper) of facade methods.. So in an effort to not cause further bugs, I used the lower casing of POST, just as it is used in the documentation.

Daedalus
  • 7,586
  • 5
  • 36
  • 61