0

I have a webapp with articles. Each article has an image. Creating (storing) of articles with images works effortlessly.

Storing images on update just doesn't. Right now, I'm just trying to upload images on already existing articles with no image. I will manage articles with attached images later.

This is my Vue page

<template>
    <AppLayout>
    <div class="bg-base-200">
    <h1 class="text-4xl p-4">Modifica articolo</h1>
    <form class="px-8 bg-base-200 pb-8" @submit.prevent="submit" enctype="multipart/form-data">
    <div class="space-y-12">
        <div class="border-b border-white/10 pb-12">
    
        <div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
            <div class="sm:col-span-4 grid sm:grid-cols-4 gap-4">
            <div class="sm:col-span-3">
                <label for="username" class="block text-sm font-medium leading-6 text-white">Titolo</label>
                <div class="mt-2">
                <div class="flex rounded-md bg-white/5 ring-1 ring-inset ring-white/10 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-500">
                    <span class="flex select-none items-center pl-3 text-gray-500 sm:text-sm"> </span>
                    <input
                    v-model="form.title"
                    type="text" class="flex-1 border-0 bg-transparent py-1.5 pl-1 text-white focus:ring-0 sm:text-sm sm:leading-6" />
                </div>
                </div>
            </div>
            </div>
    
            <div class="col-span-full">
            <label for="about" class="block text-sm font-medium leading-6 text-white">Estratto</label>
            <div class="mt-2">
                <textarea
                v-model="form.extract"
                rows="3" class="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" />
            </div>
            </div>
            
            <div class="col-span-full">
                <label for="article-body" class="block text-sm font-medium leading-6 text-white">Testo dell'articolo</label>
                <div class="mt-2 bg-white/5 rounded-md">
                    <QuillEditor  toolbar="full" v-model:content="form.body" contentType="html" theme="snow" />
                </div>
            </div>
                        <div class="col-span-full">
                            <label for="cover-photo" class="block text-sm font-medium leading-6 text-white">Foto</label>
                            
                            <!-- Show Image if it exists -->
                            <div v-if="form.media_file && form.media_file.filepath">
                                <img :src="'/storage/' + form.media_file.filepath" alt="Article Image" class="object-cover mb-10" />
                                <button @click="removeImage" class="text-red-500">X</button>
                            </div>
    
                            <!-- Show Upload Option if No Image -->
                            <div v-else class="mt-2 flex justify-center rounded-lg border border-dashed border-white/25 px-6 py-10">
                                <div class="text-center">
                                    <div class="mt-4 flex text-sm leading-6 text-gray-400">
                                        <label for="file-upload" class="relative cursor-pointer rounded-md bg-gray-900 font-semibold text-white focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2 focus-within:ring-offset-gray-900 hover:text-indigo-500">
                                            <span>Carica una foto</span>
                                            <input id="file-upload" name="media_file" type="file" class="sr-only" @change="form.media_file = $event.target.files[0]" />
                                        </label>
                                        <p class="pl-1">oppure trascinala qui</p>
                                    </div>
                                    <p class="text-xs leading-5 text-gray-400">PNG, JPG, GIF up to 10MB</p>
                                </div>
                            </div>
                        </div>
        </div>
        </div>
    
    </div>
    
    <div class="mt-6 flex items-center justify-between gap-x-6">
        <button @click="destroy" type="button" class="btn btn-error">Cancella</button>
        <button @click="$inertia.visit(route('admin.dashboard'))" type="button" class="btn btn-secondary">Annulla</button>
        <button @click="submit" type="submit" :disabled="form.processing" class="btn btn-primary ">Salva</button>
    </div>
    </form>
    </div>
    </AppLayout>
    </template>
    <script setup>
    import AppLayout from '@/Layouts/AppLayout.vue';
    import { useForm } from '@inertiajs/vue3';
    
    
    const props = defineProps({
        article: Object
    })
    
    let form = useForm({
        id: props.article.id,
        title: props.article.title,
        extract: props.article.extract,
        body: props.article.body,
        media_file: props.article.media ? props.article.media[0] : null
    })
    
    const submit = () => {
    const formData = new FormData();
    formData.append('title', form.title);
    formData.append('extract', form.extract);
    formData.append('body', form.body);
    
    // Make sure you're appending the actual file object
    if (form.media_file) {
    formData.append('media_file', form.media_file);
}

    // Use the put method to send the FormData for updating.
    form.put(route('articles.update', {id: props.article.id}), {
        body: formData
    });
    }
    
    const destroy = () =>{
        form.delete(route('articles.destroy', {id: props.article.id}));
    }
    
    </script>

And this is my Update method in ArticleController

public function update(Request $request, Article $article)
{
    dd($request);

    $validatedData = $request->validate([
        'title' => 'nullable|string|max:255',
        'extract' => 'nullable|string|max:1000',
        'body' => 'nullable|string',
        'media_file' => 'sometimes|file|mimes:jpg,jpeg,png,gif,webp,mp4,mp3,pdf|max:10240',
    ]);

    $article->update($validatedData);

    if ($request->hasFile('media_file')) {
        $file = $request->file('media_file');
        $path = $file->store('media', 'public');

        $media = new Media([
            'filepath' => $path,
            'filetype' => $this->determineFileType($file->getClientMimeType()),
            'filename' => $file->getClientOriginalName(),
            'article_id' => $article->id,
        ]);                 

        $media->save();
        $article->media()->attach($media);
    }

    //return redirect()->route('admin.dashboard');
}

I manage my routes with a Route::resource.

Again, storing images on new articles works, while they don't on update. Furthermore, the images aren't even saved in the DB. No errors anywhere

I've tried dumping the content of the request with dd($request); And something weird happens

If I changed something in the title, extract or body, I get:

#content: "{"id":3,"title":"123","extract":"Una fila di luci in movimento nel cielo.","body":"<p>Non si tratta di oggetti</p>"}

But, if try to upload an image: #content: null

(A compilation of the two, so changing both a text and uploading an image, gets the same null result)

I've spent hours trying to understand what may be causing this. Validation rules, images format, wrong routes...with no luck.

Any help is appreciated

2 Answers 2

3

Hello, please consider replacing the "put" method with "post" in the following code:

form.put(route('articles.update', {id: props.article.id}), {
    body: formData
});

Also, make a similar adjustment in the route definition. Change this:

Route::put(...)

to:

Route::post(...)

Sign up to request clarification or add additional context in comments.

2 Comments

Man...thanks. Really. It was this simple. I wasn't even sure to post this on here, but you saved me. I had to update this project for a client. Wish you the best.
@MarcoRifo did this really work for you without adding _method: 'put' as stated in the documentation ? Which laravel/inertiajs are you using ?
1

I usually just do this const formedit = useForm({id: null, _method: 'put'}) then formedit.post(route('...', formedit.id), {})

3 Comments

Yes, the documentation suggests that, but it works for me only when I do not update an image
okey how about changing <input id="file-upload" name="media_file" type="file" class="sr-only" @change="form.media_file = $event.target.files[0]" /> to this <input id="file-upload" name="media_file" type="file" class="sr-only" @change="handleFileChange" /> then in your script tag add this function function handleFileChange(e) { userForm.photo = e.target.files[0] }
Thank you for the feedback, actually the issue was just about posting a file with other related data within a form, but I fixed it yesterday. Your approach is right. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.