core/server/models/base/index.js
function onUpdating(model, attr, options) {
        if (this.relationships) {
            model.changed = _.omit(model.changed, this.relationships);
        }

        if (schema.tables[this.tableName].hasOwnProperty('updated_by')) {
            if (!options.importing && !options.migrating) {
                this.set('updated_by', String(this.contextUser(options)));
            }
        }

        if (options && options.context && !options.context.internal && !options.importing) {
            if (schema.tables[this.tableName].hasOwnProperty('created_at')) {
                if (model.hasDateChanged('created_at', {beforeWrite: true})) {
                    model.set('created_at', this.previous('created_at'));
                }
            }

            if (schema.tables[this.tableName].hasOwnProperty('created_by')) {
                if (model.hasChanged('created_by')) {
                    model.set('created_by', String(this.previous('created_by')));
                }
            }
        }

        // CASE: do not allow setting only the `updated_at` field, exception: importing
        if (schema.tables[this.tableName].hasOwnProperty('updated_at') && !options.importing) {
            if (options.migrating) {
                model.set('updated_at', model.previous('updated_at'));
            } else if (Object.keys(model.changed).length === 1 && model.changed.updated_at) {
                model.set('updated_at', model.previous('updated_at'));
                delete model.changed.updated_at;
            }
        }

        model._changed = _.cloneDeep(model.changed);

        return Promise.resolve(this.onValidate(model, attr, options));
    }
function onUpdating(model, attr, options) {
        if (this.relationships) {
            model.changed = _.omit(model.changed, this.relationships);
        }

        if (schema.tables[this.tableName].hasOwnProperty('updated_by')) {
            if (!options.importing && !options.migrating) {
                this.set('updated_by', String(this.contextUser(options)));
            }
        }

        if (options && options.context && !options.context.internal && !options.importing) {
            if (schema.tables[this.tableName].hasOwnProperty('created_at')) {
                if (model.hasDateChanged('created_at', {beforeWrite: true})) {
                    model.set('created_at', this.previous('created_at'));
                }
            }

            if (schema.tables[this.tableName].hasOwnProperty('created_by')) {
                if (model.hasChanged('created_by')) {
                    model.set('created_by', String(this.previous('created_by')));
                }
            }
        }

        // CASE: do not allow setting only the `updated_at` field, exception: importing
        if (schema.tables[this.tableName].hasOwnProperty('updated_at') && !options.importing) {
            if (options.migrating) {
                model.set('updated_at', model.previous('updated_at'));
            } else if (Object.keys(model.changed).length === 1 && model.changed.updated_at) {
                model.set('updated_at', model.previous('updated_at'));
                delete model.changed.updated_at;
            }
        }

        model._changed = _.cloneDeep(model.changed);

        return Promise.resolve(this.onValidate(model, attr, options));
    }
function onUpdating ( model , attr , options ) { if ( this . relationships ) { model . changed = _ . omit ( model . changed , this . relationships ) ; } if ( schema . tables [ this . tableName ] . hasOwnProperty ( 'updated_by' ) ) { if ( ! options . importing && ! options . migrating ) { this . set ( 'updated_by' , String ( this . contextUser ( options ) ) ) ; } } if ( options && options . context && ! options . context . internal && ! options . importing ) { if ( schema . tables [ this . tableName ] . hasOwnProperty ( 'created_at' ) ) { if ( model . hasDateChanged ( 'created_at' , { beforeWrite : true } ) ) { model . set ( 'created_at' , this . previous ( 'created_at' ) ) ; } } if ( schema . tables [ this . tableName ] . hasOwnProperty ( 'created_by' ) ) { if ( model . hasChanged ( 'created_by' ) ) { model . set ( 'created_by' , String ( this . previous ( 'created_by' ) ) ) ; } } } // CASE: do not allow setting only the `updated_at` field, exception: importing if ( schema . tables [ this . tableName ] . hasOwnProperty ( 'updated_at' ) && ! options . importing ) { if ( options . migrating ) { model . set ( 'updated_at' , model . previous ( 'updated_at' ) ) ; } else if ( Object . keys ( model . changed ) . length === 1 && model . changed . updated_at ) { model . set ( 'updated_at' , model . previous ( 'updated_at' ) ) ; delete model . changed . updated_at ; } } model . _changed = _ . cloneDeep ( model . changed ) ; return Promise . resolve ( this . onValidate ( model , attr , options ) ) ; }
Changing resources implies setting these properties on the server side
- set `updated_by` based on the context
- ensure `created_at` never changes
- ensure `created_by` never changes
- the bookshelf `timestamps` plugin sets `updated_at` automatically

Exceptions:
- importing data
- internal context
- if no context

@deprecated: x_by fields (https://github.com/TryGhost/Ghost/issues/10286)
Changing resources implies setting these properties on the server side - set updated_by based on the context - ensure created_at never changes - ensure created_by never changes - the bookshelf timestamps plugin sets updated_at automatically