Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

warpig's avatar
Level 12

Problem when updating resources

Hello, Im trying to request and process an update function to the server with Laravel 8 but im not getting back an updated post, im creating a personal blog and ive already completed the steps for index, show, and edit.

This is the form:

<form method="POST" action="/posts/{{ $post->slug }}" class="newpost-form">
        @csrf
        
        @method('PUT')

As you can see im using both @CSRF and method('PUT') for my update validation. The problem happens when i click on my submit button, i am also using a different route key on the Post model, im using the slug parameter instead of the id because it´s a blog so its easier that way, I think to identify and sharing the post.

App\Models\Post:

class Post extends Model
{
    public function getRouteKeyName()
    {
        return 'slug';
    }
    
    use HasFactory;
}

These are my routes:

Route::get('/posts', 'PostsController@index');
Route::post('/posts', 'PostsController@store');
Route::get('/posts/create', 'PostsController@create');
Route::get('/posts/{slug}', 'PostsController@show');
Route::get('/posts/{slug}/edit', 'PostsController@edit');
Route::put('/posts/{slug}', 'PostsController@update');

And this is the 'edit' function:

    public function update(Request $request, Post $post)
    {
        return redirect('posts/' . $post->slug);
    }
0 likes
20 replies
MarianoMoreyra's avatar

Hi @warpig

What are you getting back instead of an updated post? An error? The post without changes?

Just in case...your update method doesn't do anything at all with the post, so you should be getting the post as it was...

Or you haven't copied the code inside the update just to simplify?

If that's the case, please copy the entire code to see what could be going on

Tray2's avatar

Like @marianomoreyra say you need to update the post something like this should do the trick.

public function update(Post $post, PostFormRequest $request)
    {
        $post->update($request->validated());
    }

That is you are using FormRequests for your validation otherwise you can do something like this

 
public function update(Post $post, Request $request)
    {
        $post->update(['post' => $request->post]);
    }

Just add the fields to the array.

1 like
warpig's avatar
Level 12

Im getting the post without the updates yes and Im sorry, since the last time i created a function I used the route model binding method and had a few problems understanding it, i thought it would be the exact same way, its also been a while since i used PHP, kind of embarrasing... does the function need to look something like this?

    public function update(Request $request, Post $post)
    {   
        $post->title = request('title');
        $post->body = request('body');
        $post->slug = request('slug');

        return redirect('posts/' . $post->slug);
    }
MarianoMoreyra's avatar

Yes @warpig that should work provided that you have inputs with those names at your form.

Also, a cleaner way is the second example provided by @tray2 to which you could add some validation, following the offical docs, for example:

public function update(Post $post, Request $request)
{
    $validatedData = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body'  => 'required',
        'slug'  => 'required',
    ]);

    $post->update($validatedData);

    return redirect('posts/' . $post->slug);
}

ref: https://laravel.com/docs/8.x/validation#quick-writing-the-validation-logic

EDITED: tray2 said, you need the $post->update() after assigning values

1 like
Tray2's avatar

You need to put

$post->update();

before you redirect.

Or do this.

public function update(Post $post, Request $request)
    {
        $post->update([
		'title' => $request->title,
		'body' => $request->body,
		'slug' => $request->slug
	]);
    }

One thing though is that you need to validate before storing it in the database.

1 like
warpig's avatar
Level 12

Sorry most of what you guys have been answering has been returning an empty array, a 404 or an error, really dont know whats going on but i will add how the posts table looks like.. and I will specify each way i tried to apply to the function, since ive tried in several ways. What else could i share so you guys can review? Cheers! @tray2 @marianomoreyra

create_posts_table.php

    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->text('title');
            $table->string('slug');
            $table->text('body');
            $table->timestamps();
            $table->timestamp('published_at')->nullable();
        });
    }

This one threw a 404 error. When i added die($post) on this though, the browser rendered the updated post correctly, but once i removed that part it was a 404.

    public function update(Post $post, Request $request)
    {   
        $post->title = request('title');
        $post->body = request('body');
        $post->slug = request('slug');

        $post->update();

        return redirect('posts/' . $post->slug);
    }

This says Method Illuminate\Http\Request::validated does not exist.

    public function update(Post $post, Request $request)
    {   
        $post->update($request->validated());
        return redirect('posts/' . $post->slug);
    }

And since i thought maybe @tray2 wanted to type "validate" instead of "validated" on this method this happened:

Too few arguments to function Illuminate\Http\Request::Illuminate\Foundation\Providers\{closure}(), 0 passed in /Users/eduardocoello/Projects/newport/vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php on line 114 and exactly 1 expected 

This way it returned an empty array when the die method was applied, which meant that the post didnt update:

    public function update(Post $post, Request $request)
    {   
        $post->update(['post' => $request->post]);
        return redirect('posts/' . $post->slug);
    }

Also an empty array:

    public function update(Post $post, Request $request)
    {   
        $post->update([
            'title' => $request->title,
            'body' => $request->body,
            'slug' => $request->slug
        ]);
        return redirect('posts/' . $post->slug);
    }

Empty array:

    public function update(Post $post, Request $request)
    {   
        $validatedData = $request->validate([
            'title' => 'required|unique:posts|max:255',
            'body'  => 'required',
            'slug'  => 'required',
        ]);
    
        $post->update($validatedData);
        return redirect('posts/' . $post->slug);
    }
warpig's avatar
Level 12

Last attempt looks like this, threw a 404:

    public function update(Post $post, Request $request)
    {   
        $post->title = request('title');
        $post->body = request('body');
        $post->slug = request('slug');
        
        $post->update(['post' => $request->post]);
        return redirect('posts/' . $post->slug);
    }
warpig's avatar
Level 12

Complete form field

    <form method="POST" action="/posts/{{ $post->slug }}" class="newpost-form">
        @csrf
        
        @method('PUT')

        <h1> UPDATE POST </h1>
            <div class="" data-validate="Title is required">
                <span class=""> Title </span>
                <input class="" type="text" name="title" placeholder="Title" value="{{ $post->title }}">
            </div> <!-- Title field -->

            <div class="" data-validate="Body is required">
                <span class=""> Body </span>
                <textarea rows="30" cols="50" name="body" class="tinyMCE" id="bodyArea" placeholder="Body">{{ $post->body }}</textarea>
            </div> <!-- Message field --> 

        <section id="tagslug">
            <div data-validate="Slug is required">
                <span> Slug </span>
                <input type="text" name="slug" placeholder="Slug" value="{{ $post->slug }}">
            </div> <!-- Slug field end -->

            <!-- <div class="" data-validate="Tags are required">
                <span> Tags </span>
                <input type="text" name="tags" placeholder="Tags">
            </div> Tag field end -->
        </section> <!-- Slug & Tags end -->
            
            <div>
                <button class="btn-submit">Submit</button>
            </div> <!-- Submit button -->
    </form> <!-- Form end -->
MarianoMoreyra's avatar

@warpig I've just realized something...

Is this your entire Post model?

class Post extends Model
{
    public function getRouteKeyName()
    {
        return 'slug';
    }
    
    use HasFactory;
}

if that's the case, you need to add a $fillable or $guarded property to allow mass assignment.

ref: https://laravel.com/docs/8.x/eloquent#mass-assignment

Try with this for now:

class Post extends Model
{
    protected $guarded = [];

    public function getRouteKeyName()
    {
        return 'slug';
    }
    
    use HasFactory;
}

with the following update method:

    public function update(Request $request, Post $post)
    {   
        $post->title = request('title');
        $post->body = request('body');
        $post->slug = request('slug');

        $post->save();

        return redirect('posts/' . $post->slug);
    }

EDIT: Changed the ->update() to ->save() and added reference to mass assignment on docs.

warpig's avatar
Level 12

Still not working @marianomoreyra, could it be that I messed something during the edit process? Im following that series @michaloravec YES! EDIT: Changed the ->update() to ->save() and added reference to mass assignment on docs. <-- that worked though, but not on the single post page. Just on the homepage and on my index posts

Edit 2: It creates a new instance, its not updating.

MarianoMoreyra's avatar

I don't follow @warpig

Where do you say it's working? Did my last post worked and saved the updated post or not?

warpig's avatar
Level 12

@marianomoreyra what happened was that after applying the save(); instead of the update(); method, it created a new blog post instead of updating it, so the original post still exists plus the newly created.

Edit: i have 2 posts, with different slugs basically

warpig's avatar
Level 12

Sorry no, of course i would have a different slug if i also edited that slug. In cases where I DONT change the slug at all, i do end up having 2 different posts with the same slug.

MarianoMoreyra's avatar
Level 25

Actually, it's ok @warpig

If you edit the slug, it should change and not add a new one.

Please, try changing the update route to this:

Route::put('/posts/{post}', 'PostsController@update');

and see if it works...

MarianoMoreyra's avatar

OR try changing your updatemethod to accept Post $slug instead of Post $post variable (Please just try one OR the other):

    public function update(Request $request, Post $slug)
    {   
        $post->title = request('title');
        $post->body = request('body');
        $post->slug = request('slug');

        $post->save();

        return redirect('posts/' . $post->slug);
    }
1 like
warpig's avatar
Level 12

This worked, i changed every aspect of the post, including the slug and it didnt create a new entry..

Routes:

Route::put('/posts/{post}', 'PostsController@update');

Controller: (can I now adopt a simpler method for requesting an update to the server)

    public function update(Request $request, Post $post)
    {   
        $post->title = request('title');
        $post->body = request('body');
        $post->slug = request('slug');

        $post->save();
        return redirect('posts/' . $post->slug);
    }

Model:

class Post extends Model
{
    protected $guarded = [];

    public function getRouteKeyName()
    {
        return 'slug';
    }
    
    use HasFactory;
}
MarianoMoreyra's avatar

I'm glad it worked @warpig !!

The thing was that as you had different names on the route and your update parameters, it wasn't automatically binding the Post as expected.

That's why those 404 errors too.

Also, you were missing the save() method after assigning the changes... Now, you can go adding validation as I've first suggested:

public function update(Post $post, Request $request)
{
    $validatedData = $request->validate([
        'title' => 'required|max:255',
        'body'  => 'required',
        'slug'  => 'required',
    ]);

    $post->update($validatedData);

    return redirect('posts/' . $post->slug);
}

ref: https://laravel.com/docs/8.x/validation#quick-writing-the-validation-logic

1 like
warpig's avatar
Level 12

Yep, thanks! Seems like i need to dig in more about how Laravel binds functions and returns them valid.

Please or to participate in this conversation.