'Update MySQL db when element is dropped to new location (PHP & Laravel)

I'm pretty new to all of this (PHP/Laravel, MySQL and to AJAX) and at this point I just keep getting a 500 server error and I can't quite figure out what's going wrong. Any help would be very much appreciated!

I have span elements (course tiles) on a page (mysite.loc/path/page) that can be dragged and dropped into different table cells each with a unique id (set to the day+time of the cell, e.g. W1230). The drag and drop is working, and console.logs are showing that they're attaching/detaching from the elementsas expected.

On the drop, I want to update a courses_users pivot table in my MySQL db to note the new dropped location (i.e. new_day: W, new_time: 1230) by each user as authenticated, without reloading the page.

I call the AJAX to post to the update function in my TimesController, and I'm getting the following console errors at the AJAX call:

POST http://mysite.loc/update 500 (Internal Server Error)
XHR failed loading: POST "http://mysite.loc/update".

Thanks for any help.

Here's my javascript for the drag and drop with the ajax call (inside script tags in my page's main php file):

$(document).ready(function(){
    var parent;
    $("span").on("dragstart", function (event) {
        var tile = event.originalEvent.dataTransfer;
        tile.setData('Text', $(this).attr('id'));
        parent = event.target.parentNode.id;
    });
        //prevent default actions on dragenter, dragoover
        $('table td').not("#meettime").on("dragenter dragover", function (event) {
        event.preventDefault();
    });
    //the element is dropped.
        $('table td').not("#meettime").on("drop", function (event) {
            event.preventDefault();
            if (event.type === "drop") {
                var tile_id = event.originalEvent.dataTransfer.getData('Text',$(this).attr('id'));
                var drop_location = $(this).attr("id"); 
                if (drop_location == parent) {
                    event.preventDefault();
                } else {
                    var crn = tile_id.substr(3, 5); //crn is the course's unique reference number
                    var new_day = drop_location.slice(-22,-4); 
                    var new_time = drop_location.slice(-4); 
                    de=$('#'+tile_id).detach();
                    var q = $(de); 
                    q.attr("class","tile changed");
                    de.appendTo($(this));
                                        
                    tileData = {'crn': crn, 'new_day': new_day, 'new_time': new_time};
                    $.ajax({
                        headers: {
                            'X-CSRF-Token': '{{ csrf_token() }}',
                        },
                        type:'POST',
                        url: '{{url("update")}}',
                        dataType: 'json',
                        data: tileData,
                        success: function(){
                            alert('Updated');
                        }
                    });
                }
            }
        });
});

Here is the route in my web.php

Route::middleware(['auth:sanctum', 'verified'])->post('update', [TimesController::class, 'update']);

The update() function in my TimesController.php

namespace App\Http\Controllers;
use App\Models\Time;
use App\Models\Course;
use App\Models\User;
use Illuminate\Http\Request;
use Auth;
[...]
public function update(Request $request)
    {
     $user = Auth::user();
     $user = $user->id; 

     $course = $user->courses()->where("crn", "=", $request->crn)->get();
            
     if ($course) {
         $course->pivot->new_day = $request->new_day;
         $course->pivot->new_time = $request->new_time;
         $course->pivot->save();
     } else {
         $request->user()->courses()->save($course, ['crn' => $request->notes, 'new_day' => $request->new_day, 'new_time' => $request->new_time]);
     }
            
     return 'Update complete. Check the `course_user` table to confirm.';

     }


Solution 1:[1]

To anyone who may have looked at this, I ended up figuring out from my Laravel logs that my problem was with with the TimesController trying to update pivot values on a non-Object.

In case it's helpful for someone else, here's my updated update() function from my TimesController. Note that this function works to both save a new change (inserting a new record to the course_user pivot table) and to update an existing course.

    public function update(Request $request)
    {
        $crn = $request->crn;
        $course = Course::findByCRN($crn);
        $user = Auth::user();


        $existingcourse = $user->courses()->where('courses.id', $course->id)->first();
        
        if($existingcourse) {
            $existingcourse->pivot->new_day = $request->new_day;
            $existingcourse->pivot->new_begin_time = $request->new_time;
            $existingcourse->pivot->save();
        } else {
            $user->courses()->save($course, ['new_day' => $request->new_day, 'new_begin_time' => $request->new_time]);
        }
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 strugglebus