robobalasko's avatar

How to stop eloquent trying to set updated_at

Hey guys,

I would like to ask for any suggestions about how to stop Eloquent trying to set the updated_at columns in my DB table, which is not present there. For this particular table, I only require the created_at to be set.

I haven an override on the setUpdatedAt method

public function setUpdatedAt($value) {  }

which as Google told me should stop laravel from setting the updated_at parameters on the model; however, it does not.

Thanks to everyone in advance.

0 likes
21 replies
bestmomo's avatar

Anyway it should work :

    /**
     * Set the value of the "updated at" attribute.
     *
     * @param  mixed  $value
     * @return void
     */
    public function setUpdatedAt($value)
    {
        $this->{static::UPDATED_AT} = $value;
    }
2 likes
raysmithdev's avatar
public function setUpdatedAtAttribute($value)
{
    // to Disable updated_at
}

or

protected $timestamps  = false;
3 likes
robobalasko's avatar
public function setUpdatedAtAttribute($value)

is not present in Laravel 5. What is interesting though, the exception thrown, shows this:

at Builder->update(array('read' => '1', 'updated_at' => '2015-02-24 22:16:39')) in Builder.php line 288
at Builder->update(array('read' => '1')) in Model.php line 1559
at Model->performUpdate(object(Builder), array()) in Model.php line 1492
at Model->save() in MessagesRepository.php line 97
at MessagesRepository->update(object(Message), array('read' => '1')) in MessagesController.php line 55

by which it seems that even though the Builder object receives the input array without the updated_at attribute set, it sets it afterwards, which it shouldn't...

1 like
robobalasko's avatar

The only thing I do is that my Message model class extends the Model class and overrides the

public function setUpdatedAt($value)

I just put that method into my Message model and left the body of the method empty so that the updated_at attribute is not set, which does not seem to be true. How come that the updated_at attribute is being set anyway in the Builder instance?

bestmomo's avatar

@robobalasko

Looking in core and get this :

/**
 * Update a record in the database.
 *
 * @param  array  $values
 * @return int
 */
public function update(array $values)
{
    return $this->query->update($this->addUpdatedAtColumn($values));
}

Looks like for any update builder add updated_at column :

/**
 * Add the "updated at" column to an array of values.
 *
 * @param  array  $values
 * @return array
 */
protected function addUpdatedAtColumn(array $values)
{
    if ( ! $this->model->usesTimestamps()) return $values;

    $column = $this->model->getUpdatedAtColumn();

    return array_add($values, $column, $this->model->freshTimestampString());
}

So if you set timestamps builder will always update updated_at...

xingfucoder's avatar

Hi, maybe you could use the boot() method from a BaseModel and make use of the static::updating event for removing any updated_at content.

public function boot()
{
    parent::boot();

    static::creating(function()
    {
        static::setUpdatedAtAttribute() //Call a custom setUpdatedAtAttribute function
    });
}

public static function setUpdatedAtAttribute()
{
   //put here your content.
}

Hope it helps you.

JarekTkaczyk's avatar
Level 53

@robobalasko There is no reliable way to do it, but disabling timestamps for the model, then add creating event handler, like mentioned above:

public $timestamps = false;
// ...
    // boot
    static::creating( function ($model) {
        $model->setCreatedAt($model->freshTimestamp());
    });

It will take care of created_at column for you.

9 likes
robobalasko's avatar

@JarekTkaczyk

After an hour of digging in the core I found a way how to accomplish this...

First of all, I extended the default model class with a custom BaseModel class that all my other models now extend. Then, I added a new attribute to my BaseModel class, along with an accompanying method:

protected $useUpdatedAt = true;

public function usesUpdatedAt()
{
    return $this->useUpdatedAt;
}

Finally, I modified the updateTimestamps() method of the core Model class to use an if when setting the updated_at column like this:

if ($this->usesUpdatedAt())
{
    $this->setUpdatedAt($time);
}

and also the first line of the Builder class' addUpdatedAtColumn method like this:

if ( ! $this->model->usesTimestamps() || ! $this->model->usesUpdatedAt()) return $values;

AND IT WORKS!

Now, in every model where the updated_at timestamp is not required, I only have to set the $useUpdatedAt param of that particular model class to false.

Not sure if this is the best way to go, but certainly, it is the only one I could come up with myself... Anyway, looking at it now, yours is much cleaner, so I'll probably use that creating model event since there won't be many Models that would not require updated_at being set.

JarekTkaczyk's avatar

@robobalasko I suppose you overriden the method on Eloquent\Builder in the core files, which is not a good idea. It will be reset with next composer update. So, yes, it can be achieved that way, but it's not reliable and a bit longer ;)

1 like
kabircse's avatar

Try to use this.

for disabling updated_at

         public function setUpdatedAt($value){
            ;
         }

for disabling created_at

       public function setCreatedAt($value){
            ;
        }

For disabling both just use

 public $timestamps  = false ;
1 like
Azzikker's avatar

To stop eloquent on trying to set "updated_at" and "created_at", you need to do the following

1st:

Locate the file... "laravel folder"\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php

2nd:

Open this file then find the follwoing functions:

updateTimestamps() getUpdatedAtColumn() getCreatedAtColumn()

3rd:

Inside the function updateTimestamps(), just comment the following codes inside the if conditions:

    $time = $this->freshTimestamp();

    if (! $this->isDirty(static::UPDATED_AT)) {
        //$this->setUpdatedAt($time);
    }

    if (! $this->exists && ! $this->isDirty(static::CREATED_AT)) {
        //$this->setCreatedAt($time);
    }

Inside the function getUpdatedAtColumn(), just comment this code:

//return static::CREATED_AT;

Inside the function getCreatedAtColumn(), just comment this code:

//return static::UPDATED_AT;

Then after that, the eloquent will never set the field "updated_at" and "created_at". Hope it helps. :)

raulursu's avatar

If you want to disable it for only one or few objects you can try this

class YourModelName extends Model { /** * @var string */ protected $table = "your_table_name_here";

/**
 * @var array
 */
protected $guarded = [];

/**
 * @var string
 */
public $updated_at = '';

}

It seems if you add only the following line in your object declaration is just enough. Not elegant but this works for me.

public $updated_at = '';

.. and sorry for my bad English :D

asprague's avatar

I borrowed from @raulursu. This works for me when only using created_at.

protected $dates = ['created_at'];
protected $updated_at = '';

I'm using $fillable and thus using $guarded is not recommended.

1 like
igor-chepurnoi's avatar

You can disable updated_at attribute as follows

/**
* The name of the "updated at" column.
*
* @var string
*/
const UPDATED_AT = null;

works for laravel 5.5

2 likes
razz's avatar

The easiest way for me was like what @raysmithdev mentioned here, however a slight modification if I may

instead of: protected $timestamps = false;

use: public $timestamps = false;

Shahrukh4's avatar

just declare the public timestamps variable to false and everything will work great.

public $timestamps = false;
2 likes
arukomp's avatar

You'll often encounter tables where you don't even want to have an updated_at column because you'll never touch the records after their creation. The easiest way (for me at least) to achieve it is this:

  • Migration. Replace the default $table->timestamps(); call with a new one like this:
$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));

this will continue filling the created_at column automatically and will be handled by MySQL.

  • Model. Disable the timestamps because you no longer want to rely on Laravel generating the timestamps. Also, you might want to add a $dates cast attribute, just to make sure that the created_at column is always being cast to a Carbon instance.
class SomeModel extends Model
{
    public $timestamps = false;
    
    protected $dates = ['created_at'];
    ...
}
BlackDiamond's avatar

If you are using 5.5.x:

const UPDATED_AT = null;

And for 'created_at' field, you can use:

const CREATED_AT = null;

Make sure you are on the newest version. (This was broken in Laravel 5.5.0 and fixed again in 5.5.5).

Please or to participate in this conversation.