Laravel Eloquent $model->save() not saving but no error
Asked Answered
V

16

40

When updating my Post model, I run:

$post->title = request('title');
$post->body = request('body');

$post->save();

This does not update my post. But it should according to the Laravel docs on updating Eloquent models. Why is my model not being updated?

Post model:

class Post extends Model
{
    protected $fillable = [
        'type',
        'title',
        'body',
        'user_id',
    ];

   ....
}

Post controller:

public function store($id)
{
    $post = Post::findOrFail($id);

    // Request validation
    if ($post->type == 1) {
        // Post type has title
        $this->validate(request(), [
            'title' => 'required|min:15',
            'body' => 'required|min:19',
        ]);

        $post->title = request('title');
        $post->body = request('body');
    } else {
        $this->validate(request(), [
            'body' => 'required|min:19',
        ]);

        $post->body = request('body');
    }

    $post->save();

    return redirect('/');
}

Bonus info

Running dd($post->save()) returns true.

Running

$post->save();

$fetchedPost = Post::find($post->id);
dd($fetchedPost);

shows me that $fetchedPost is the same post as before without the updated data.

Virgulate answered 24/10, 2017 at 20:55 Comment(20)
are you sure you have the "body" field under POST model ?Oligochaete
@MoeenBasra yes, sorry! I had cleaned up the other code to make it more readable and relevant (took out irrelevant parts like code cleaning that I've already validated, etc.) and I forgot to change that variable.Virgulate
What does return dd($post->save())?Help
@IvankaTodorova dd($post->save()) returns true. I added this in the question.Virgulate
I guess laravel 5.5 change some validation system. I'm adding an answer try that.Oligochaete
What dd($post->isDirty()) return?Chaeta
Are you 100% certain you're looking at the right database?Ventriloquy
I think the problem is you are not accepting the request sent from the form in the store function. @jacobHerzl
@AndersonAndrade it returned false ...... I followed this SO question to ensure I was doing it right.Virgulate
request should be $request?Kristelkristen
@Ventriloquy yes. I ran tests to check.Virgulate
both $request injected to the store function or request helper returns the same thing. As request is binded with singleton pattern with container.Oligochaete
if validation isn't the issue here too your request('title') and/or request('body') must be identical?Kristelkristen
@LarsMertens just ran this test: Original title: This is my title. dd(request('title')): This is my title and now it has been updated.Virgulate
How do the post types come into it? If the post type does not equal 1, then you are not setting the title however it is a required field.Zymogen
@Zymogen if the post type is not 1 then title is not requiredVirgulate
Please check either you have set mutator in your model class or there is no id in model object?Snell
What worked for me was setting a protected property $primaryKey in my model.Intoxicant
Make sure your Post model is extending Illuminate\Database\Eloquent\Model. I was extending Illuminate\Database\Eloquent\Relations\MorphPivot and had the same problem as yours.Zipper
put the rest of your code, how did you find the $ post? because there we can arrive at a conclusion, depending on the way the search can not use save.Chadd
B
25

Check your database table if the 'id' column is in uppercase 'ID'. Changing it to lower case allowed my save() method to work.

Bestiality answered 10/12, 2018 at 5:16 Comment(5)
You don't have to change it. You could just define the primary key name in your model by adding protected $primaryKey = 'Id'; to your model. this in case the primary key is "Id" not "id"Secure
This was my issue, I am working on a database that existed and ids are not called Id or ID but a completely different thing. What makes this hard to catch is that I am using ` protected $primaryKey = 'myid'; ` And it is working fine for querying, but if it isn't an exact match, it won't save, the ID of my table was in upper case, changed it and voila, problem solved, your comment opened up my eyes.Obadias
Damn MSSQL NON CASE SENSITIVE! Find the Model but Eloquent cannot save correctly.Gilbertson
instead of changing from db change value from protected $primaryKey = 'Id'; modelVenezuela
my mysql USER_ID was capitalized, but I set $primaryKey = 'user_id'. Everything worked perfectly, except it would NOT save to the database. Uppercasing it worked. Thank you!Scrivenor
D
18

I had the same and turned out to be because I was filtering the output columns without the primary key.

$rows = MyModel::where('...')->select('col2', 'col3')->get();
foreach($rows as $row){
    $rows->viewed = 1;
    $rows->save();
}

Fixed with

$rows = MyModel::where('...')->select('primary_key', 'col2', 'col3')->get();

Makes perfect sense on review, without the primary key available the update command will be on Null.

Divide answered 15/5, 2019 at 4:17 Comment(3)
This was the cause of the issue for me as well. Thank you!Howlet
This got me too. Have to be sure to include the primary key in the model in order to update it with save(). Never knew that.Chaldean
yeap, this was my problem, forgot the primary key as well :) thank!Cabochon
A
7

I had the same problem and changing the way I fetch the model solved it!

Was not saving even though everything was supposedly working just as you have mentioned:

$user = User::find($id)->first(); 

This is working:

$user = User::find($id);
Auriga answered 26/6, 2018 at 0:19 Comment(1)
remembering that it is functional to use the find method together with the save, but with some others the save does not work ... also remembering that find only uses the primaryKeyChadd
I
6

You have to make sure that the instance that you are calling save() on has the attribute id

Intervene answered 23/4, 2020 at 10:2 Comment(1)
On the code shown, he is doing $post = Post::findOrFail($id);, so it must have an id setAnthia
O
4

Since Laravel 5.5 laravel have change some validation mechanism I guess you need to try this way.

public function store(Request $request, $id)
{
    $post = Post::findOrFail($id);

    $validatedData = [];

    // Request validation
    if ($post->type == 1) {
        // Post type has title
        $validatedData = $request->validate([
          'title' => 'required|min:15',
          'body' => 'required|min:19',
      ]);
    } else {
      $validatedData = $request->validate([
        'body' => 'required|min:19',
    ]);
    }

    $post->update($validatedData);

    return redirect('/');
}
Oligochaete answered 24/10, 2017 at 21:8 Comment(1)
can you past the dump of $validatedData just before $post->update();Oligochaete
D
4

Running dd() inside a DB::transaction will cause a rollback, and the data in database will not change.

The reason being, that transaction will only save the changes to the database at the very end. Ergo, the act of running "dump and die" will naturally cause the script to cease and no therefore no database changes.

Davilman answered 16/1, 2020 at 14:31 Comment(0)
T
3

Check your table if primary key is not id ("column name should be in small letters only") if you have set column name with different key then put code in your Model like this

protected $primaryKey   = 'Id';

So this might be one of the possible solution in your case also if your column name contains capital letters. Yes this worked for me fine, You should have column names in small letter, If you don't have then mention it in the model file, mainly for primaryKey by which your model will try to access database.

Tyson answered 16/4, 2021 at 6:50 Comment(0)
W
2

For use save () method to update or delete if the database has a primary key other than "id". need to declare the attribute primaryKey = "" in the model, it will work

Wheelhorse answered 16/4, 2021 at 7:49 Comment(0)
V
2

If you using transactions. Do not forget call DB::commit();

It must look like this:

try{
    DB::beginTransaction();
    // Model changes
    $model->save();
    DB::commit();
}catch (\PDOException $e) {
    DB::rollBack();
}
Vanhouten answered 28/6, 2022 at 1:50 Comment(0)
L
2

I have the same issue although there are try / catch block in controller@action() but there were no response, it just stops at $model->save(); there is no log entry either in apache error.log or laravel.log. I have just wrapped the save() with try / cactch as follows, that helped me to figure out the issue

    try{
        $model->save();
    }
    catch (\PDOException $e) {
        echo $e->getMessage();
    }
Leaper answered 16/11, 2022 at 4:30 Comment(2)
Thank you, this worked for me. I'm baffled why it doesn't trigger an unhandled exception without the try block, or even with it using catch (\Exception $e), it still didn't trigger the catch block. Adding PDOException worked.Riane
If you are using the latest version of laravel please try clearing the cache using the following php artisan optimize:clearLeaper
C
1

The issue stems from the database containing multiple results for the query involving Laravel Model.

What I'm trying to convey is that if you use methods like find, findOrFail, or any other query followed by ->first(), you'll obtain one of the records, but it's almost certain that there's at least one more record that matches the query. I understand my response might be somewhat delayed, but it could potentially assist others encountering the same problem.

To resolve this, consider adding additional criteria to your query to ensure that you receive only one result as a response. This step will help guarantee accurate outcomes.

Crosseye answered 10/8, 2023 at 17:1 Comment(1)
Thank you. You also need to make sure the primary key is in the select statement if you're using one.Nightspot
H
0

Try this

public function store($id,Request $request)
{
    $post = Post::findOrFail($id);

    // Request validation
    if ($post->type == 1) {
        // Post type has title
         $request->validate([
            'title' => 'required|min:15',
            'body' => 'required|min:19',
        ]);
        $post->update([
              'title' => request('title');
              'body' => request('body');
             ]);
    } else {
         $request->validate([
            'body' => 'required|min:19',
        ]);

        $post->update([
              'body' => request('body');
             ]);
    }

    return redirect('/');
}
Herzl answered 24/10, 2017 at 21:11 Comment(0)
H
0

In my experience, if you select an Eloquent model from the db and the primary_key column is not part of the fetched columns, your $model->save() will return true but nothing is persisted to the database.

So, instead of doing \App\Users::where(...)->first(['email']), rather do \App\Users::where(...)->first(['id','email']), where id is the primary_key defined on the target table.

If the (sometimes micro-optimization) achieved by retrieving only a few columns is not really of importance to you, you can just fetch all columns by doing \App\Users::where(...)->first(), in which case you do not need to bother about the name of the primary_key column since all the columns will be fetched.

Hessney answered 23/5, 2019 at 15:0 Comment(0)
N
0

You can not use $post->save() to update a record, YOU MUST USE $post->update(). But note that laravel uses to firstly check if the model was retrieved by using Eloquent manner. There is a property public $exists on each model instance. You use to switch it into true.

public function store($id)
{
    $post = Post::findOrFail($id);
    $validated = [];
    // Request validation
    if ($post->type == 1) {
        // Post type has title
        $validated = $this->validate(request(), [
            'title' => 'required|min:15',
            'body' => 'required|min:19',
        ]);
    } else {
        $validated = $this->validate(request(), [
            'body' => 'required|min:19',
        ]);
    }

    // ----------------------------------
    $post->exists = true;
    $success = $post->update($validated);
    // ----------------------------------

    return redirect('/');
}
Neaten answered 20/4 at 14:27 Comment(0)
M
0

Something I've just experienced - if you have a typo in your attribute lets say you have ORDERDEADLINE but you spell it ORDEDEADLINE and assign the attribute and use save();

It doesn't throw an error you can catch but the process will stop and the object won't update either.

Musa answered 25/7 at 8:37 Comment(0)
C
-1

I have been experiencing the same issue and found a workaround. I found that I was unable to save() my model within a function called {{ generateUrl() }} on my home.blade.php template. What worked was moving the save() call to the controller that returns the home.blade.php template. (IE, save()ing before the view is returned, then only performing read operations within {{ generateUrl() }}.)

I was (and am) generating a state to put in a URL on page load:

<!--views/home.blade.php-->

<a href="{{ EveAuth::generateUrl() }}">Add Character</a>

Below is what did not work.

// Providers/EveAuth.php

function generateUrl()
{
    $authedUser = auth()->user();
    if (!$authedUser) {
        return "#";
    }
    $user = User::find($authedUser->id);
    $user->state = str_random(16);
    $user->save();

    $baseUrl = 'https://login.eveonline.com/oauth/authorize?state=';

    return $baseUrl . $user->state;
}

This was able to find() the User from the database, but it was unable to save() it back. No errors were produced. The function appeared to work properly... until I tried to read the User's state later, and found that it did not match the state in the URL.

Here is what did work.

Instead of trying to save() my User as the page was being assembled, I generated the state, save()d it, then rendered the page:

// routes/web.php

Route::get('/', 'HomeController@index');

Landing at the root directory sends you to the index() function of HomeController.php:

// Controllers/HomeController.php

public function index()
{
    $authedUser = auth()->user();
    if ($authedUser) {
        $user = User::find($authedUser->id);
        $user->state = str_random(16);
        $user->save();
    }
    return view('home');
}

Then, when generating the URL, I did not have to save() the User, only read from it:

// Providers/EveAuth.php

function generateUrl()
{
    $authedUser = auth()->user();
    $user = User::find($authedUser->id);

    $baseUrl = 'https://login.eveonline.com/oauth/authorize?state=';

    return $baseUrl . $user->state;
}

This worked! The only difference (as far as I see) is that I'm save()ing the model before page assembly begins, as opposed to during page assembly.

Constringent answered 21/7, 2018 at 19:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.