How to Upload Files with Laravel, Inertia js and Vue js Part 2
In the second part of this tutorial we are going to see how to append a custom new attribute to the Laravel model, we will add a Profile component and routes.
Append a custom new attribute to the Laravel model
Next, inside the User's model, we append a custom new attribute "image" which will return the full path of the user's profile picture.
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Support\Facades\Storage;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
'photo_url'
];
protected $appends = ['image'];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getImageAttribute() {
if(Storage::disk('public')->exists(auth()->user()->photo_url)) {
return asset('storage/'.$this->photo_url);
}
return $this->photo_url;
}
}
Create the Profile Component
Next, we create the Profile Component.
<template>
<div class="container">
<div className="row my-5">
<div v-if="$page.props.flash.message" :class="`my-3 ${$page.props.flash.class}`">
{{ $page.props.flash.message }}
</div>
<div v-if="form.errors.photo_url" class="text-white bg-danger p-2 rounded my-2">{{ form.errors.photo_url }}</div>
<div className="col-md-3">
<div className="card">
<div className="card-body">
<img :src="user.image" alt="Profile Image" class="img-fluid rounded">
<form @submit.prevent="uploadFile">
<div class="mt-3">
<label for="formFile">Change profile image</label>
<input type="file" @input="setPhotoUrl"
id="formFile" class="form-control mt-1">
</div>
<div class="mt-2">
<button
:disabled="!form.photo_url"
class="btn btn-sm btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-body">
<ul class="list-group">
<li class="list-group-item">
<span class="fw-bold">Username:</span>
{{ user.name }}
</li>
<li class="list-group-item">
<span class="fw-bold">Email:</span>
{{ user.email }}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { useForm, usePage } from '@inertiajs/vue3';
import { computed } from 'vue';
const form = useForm({
photo_url: ''
});
const setPhotoUrl = (e) => {
form.photo_url = e.target.files[0];
}
const user = computed(() => usePage().props.user);
const uploadFile = () => {
form.post(route('profile'), {
onSuccess: () => {
form.reset('photo_url')
}
});
}
</script>
<style>
</style>
Add routes
Finally, we add the routes.
Route::get('user/profile', [ProfileController::class, 'profile'])->name('profile');
Route::post('user/profile', [ProfileController::class, 'updateProfileImage'])->name('profile');