Search code examples
laravelvue.jsaxiosvuexhttp-status-code-500

Laravel8 | Vuex: POST error 500 (Internal Server Error)


I've been learning Vue and Laravel for the last 2 months and recently I started to work on a project in order to apply all the knowledge I've learned so far. I set several GET and POST routes successfully but for some reason, this request keeps failing. I'm trying to set a simple POST request using Vuex, Laravel and Axios but I keep on getting the 500 (Internal Server Error) and I'm not sure what is causing it. I have the feeling that it may be that the Model is not correctly set up, bcs if I output the data that the controller received, it looks correct but when I instantiate the model and save the data to DB I get the error.

I would really appreciate any help or feedback on my code since I'm in a early stage of my learning curve and there are some things that I'm sure could be optimized.

Route:

//StreamingProviders
Route::get('/api/all-streaming-providers', [StreamingProviderController::class, 'getAllStreamingProviders']);
Route::post('/api/add-streaming-providers', [StreamingProviderController::class, 'addStreamingProviders']);

Controller:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Repository\Dictionaries\StreamingProvidersList;
use App\Models\StreamingProvider;

class StreamingProviderController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function getAllStreamingProviders()
    {
        $streamingProviders = StreamingProvidersList::$map;
        
        return response()->json([
            'allProviders' => $streamingProviders
        ]);
    }

    public function addStreamingProviders(Request $request, StreamingProvider $userStreamingProviders)
    {
        $user = auth()->user();
        $data = $request->all();
    
        $userStreamingProviders = new StreamingProvider();
        $userStreamingProviders->user_id = $user['id'];
        $userStreamingProviders->Netflix = $request->input('Netflix');
        $userStreamingProviders->Amazon_Prime_Video = $request->input('Amazon Prime Video');
        $userStreamingProviders->Sky_Ticket = $request->input('Sky Ticket');
        $userStreamingProviders->Disney_Plus = $request->input('Disney Plus');
        $userStreamingProviders->HBO_Video = $request->input('HBO Video');
        $userStreamingProviders->save();

        return response()->json([
            'streamingProviders' => $userStreamingProviders            
        ]);
    }
}

FormComponent.vue

<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="card">
                <div class="card-header">
                    <h2>Select your streaming country</h2>
                </div>
                <form @submit.prevent="updateUserDetails()">
                    <div class="card-body">                   
                        <div class="form-control">
                            <select class="selectpicker" id="countryList">
                                <option v-for="(value, name) in getCountriesList" :key="name" :value="name">
                                    {{ value }}
                                </option>
                            </select>
                        </div>   
                        <div v-for="(value, name) in getAllStreamingProviders" :key="name" class="form-check">
                            <input v-model="streamingProviders[value]"
                                type="checkbox"
                                :id="name"
                                :value="value"
                                :name="streamingProviders[value]"
                                class="form-check-input" />
                            <label>{{ value }}</label>
                        </div>
                    </div>
                    <div class="card-footer">
                        <button type="submit" class="btn btn-success center-text">Save</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</template>

<script>
import { mapGetters } from 'vuex';
import router from '../../routes/index';

export default {
    name: 'edituserdetails',
    data() {
        return {
            value: '',
            streamingProviders: {
                'Netflix': false,
                'Amazon Prime Video': false,
                'Disney Plus': false,
                'HBO Video': false,
                'Sky Ticket': false
            }
        }
    },
    created() {
        this.$store.dispatch('getCountriesList'),
        this.$store.dispatch('getAllStreamingProviders')
    },
    methods: {
        updateUserDetails() {
            const country = {
                'id': $('#countryList').children("option:selected").val(),
                'name': $('#countryList').children("option:selected").text()
            };
            this.$store.dispatch('updateUserStreamingProviders', this.streamingProviders);

            this.$store.dispatch('updateCountry', country).then(() => {
                router.push('/user-settings');
            });
        }
    },
    computed: {
        ...mapGetters(['getCountriesList', 'getAllStreamingProviders']),
    }
}
</script>

Vuex store:

import axios from "axios";

const state = {
    userName: "",
    country: "",
    countriesList: {},
    allStreamingProviders: {},
    userStreamingProviders: []
};

const mutations = {
    UPDATE_USERNAME(state, payload) {
        state.userName = payload;
    },
    GET_COUNTRIES_LIST(state, payload) {
        state.countriesList = payload;
    },
    UPDATE_COUNTRY(state, payload) {
        state.country = payload;
    },
    GET_ALL_STREAMING_PROVIDERS(state, payload) {
        state.allStreamingProviders = payload;
    },
    UPDATE_STREAMING_PROVIDERS(state, payload) {
        state.userStreamingProviders = payload;
    }
};

const actions = {
    updateUserData({ commit }) {
        axios.get("/api/user").then(response => {
            commit("UPDATE_USERNAME", response.data.name);
            commit("UPDATE_COUNTRY", response.data.country);
        });
    },
    getCountriesList({ commit }) {
        axios.get("/api/countries-list").then(response => {
            commit("GET_COUNTRIES_LIST", response.data.list);
        });
    },
    updateCountry({ commit }, country) {
        axios
            .post("/api/update-country", country)
            .then(response => {
                commit("UPDATE_COUNTRY", response.data.country);
            })
            .catch(err => {
                console.log(err);
            });
    },
    getAllStreamingProviders({ commit }) {
        axios.get("/api/all-streaming-providers").then(response => {
            commit("GET_ALL_STREAMING_PROVIDERS", response.data.allProviders);
        });
    },
    updateUserStreamingProviders({ commit }, streamingProviders) {
        axios
            .post("/api/add-streaming-providers", streamingProviders)
            .then(response => {
                commit(
                    "UPDATE_STREAMING_PROVIDERS",
                    response.data.streamingProviders
                );
            })
            .catch(err => {
                console.log(err);
            });
    }
};

const getters = {
    getUserName: state => state.userName,
    getCountry: state => state.country,
    getCountriesList: state => state.countriesList,
    getAllStreamingProviders: state => state.allStreamingProviders
};

const userStore = {
    state,
    mutations,
    actions,
    getters
};

export default userStore;

Streaming Provider Model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class StreamingProvider extends Model
{
    use HasFactory;

     /**
     * Attributes that are mass assignable
     * 
     * @var array
     */
    protected $fillable = ['user_id', 'Netflix', 'Amazon_Prime_Video', 'Sky_Ticket', 'Disney_Plus', 'HBO_Video'];

    protected $table = 'streaming_provider';

    protected $cast = [
        'Netflix' => 'boolean',
        'Amazon_Prime_Video' => 'boolean',
        'Sky_Ticket' => 'boolean',
        'Disney_Plus' => 'boolean',
        'HBO_Video' => 'boolean'
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Do I have to cast the data before saving it to DB? Are the boolean properties considered $fillable ??

migration:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class StreamingProvidersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('streaming_provider', function (Blueprint $table) {
            $table->id();
            $table->string('user_id');
            $table->boolean('Netflix')->default(0);
            $table->boolean('Amazon_Prime_Video')->default(0);
            $table->boolean('Sky_Ticket')->default(0);
            $table->boolean('Disney_Plus')->default(0);
            $table->boolean('HBO_Video')->default(0);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('streaming_provider');
    }
}

Laravel.log:

[2021-10-27 09:12:39] local.ERROR: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' (SQL: insert into `streaming_provider` (`user_id`, `Netflix`, `Amazon_Prime_Video`, `Sky_Ticket`, `Disney_Plus`, `HBO_Video`, `updated_at`, `created_at`) values (1, 1, 1, 0, 0, 0, 2021-10-27 09:12:39, 2021-10-27 09:12:39)) {"userId":1,"exception":"[object] (Illuminate\\Database\\QueryException(code: 42S22): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' (SQL: insert into `streaming_provider` (`user_id`, `Netflix`, `Amazon_Prime_Video`, `Sky_Ticket`, `Disney_Plus`, `HBO_Video`, `updated_at`, `created_at`) values (1, 1, 1, 0, 0, 0, 2021-10-27 09:12:39, 2021-10-27 09:12:39)) at C:\\xampp\\htdocs\\laravel_vue\\Fullstack_Project_Movie_III\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:703)
[previous exception] [object] (PDOException(code: 42S22): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' at C:\\xampp\\htdocs\\laravel_vue\\Fullstack_Project_Movie_III\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:486)


Thanks you all!!


Solution

  • You have this error because $table->timestamps(); is missing from your migration so you have to add it, Laravel will automatically create updated_at and created_at column for you. For every entry and update in laravel it automatically assign value to these columns, so obviously you get this error when they are missing from your database.

    After, your migration will look like this:

    `Schema::create('streaming_provider', function (Blueprint $table) {
            $table->id();
            $table->string('user_id');
            $table->boolean('Netflix')->default(0);
            $table->boolean('Amazon_Prime_Video')->default(0);
            $table->boolean('Sky_Ticket')->default(0);
            $table->boolean('Disney_Plus')->default(0);
            $table->boolean('HBO_Video')->default(0);
            $table->timestamps();
        });`