How do I save an Ember Data record without submitting it to the backend?

So Ember Data Model has a deleteRecord() that performs a destroyRecord() without submitting it to the backend.

How do I do save() without submitting it to the backend?

The reason I need it is that I'm using a custom service to batch-save multiple records of different types (models) in one request. I'm successfully sending the requests, and records are persisted on the backend.

But as the request does not go through the Ember Data pipeline, the response from server will be discarded unless I handle it manually.

Basically, I have this in a service:

// Accepts an array of records of mixed types,
// both existing and new
batchSave (records) {             

  this
    .customAjax(records)          // The records are persisted
    .then(payload => {            // Response from the backend with updated records
      store.pushPayload(payload); // Now all records have been updated with their current state

      // Now all the records are in their current state.
      // But they are still dirty!
      // How do I mark them clean and saved
    });

I've seen this but it seems to discard dirty attributes, while I want dirty attributes to become clean.

I've also tried store.didSaveRecord() but after it records are still dirty.

Upvotes: 5

Views: 3840

Answers (3)

Tom Netzband
Tom Netzband

Reputation: 1110

Disclaimer: This isn't an ideal solution and I hope someone can point us both in a better direction.

Edit: torazaburo's solution on this thread seems like the best way to go.


I've run into the same situation and haven't found a great solution. I ended up writing a custom adapter and added a service to just return true in updateRecord if the service had a flag of preventRequest: true.

Example:

// services/prevent-request.js
export default Ember.Service.extend({
  prevent: false // default
});

// adapters/post.js
export default ApplicationAdapter.extend({
  preventSave: Ember.inject.service(),

  updateRecord (store, type, snapshot) {
    if (this.get('preventSave.prevent')) {
      this.set('preventSave.prevent', false);
      return true;
    }

    this._super(store, type, snapshot);
  }
});

// controllers/some-controller.js
export default Ember.Controller.extend({
  preventSave: Ember.inject.service(),

  actions: {
    someAction () {
      (...)
      this.get('preventSave').set('prevent', true);
      post.save();
    }
  }
});

Upvotes: 2

Vítor Martins
Vítor Martins

Reputation: 1440

According to Ember Guides using store.createRecord() will created the record and add it to the store but it won't make a request to the backend.

Example:

store.createRecord('post', {
  title: 'Rails is Omakase',
  body: 'Lorem ipsum'
});

The store object is available in controllers and routes using this.store.

Then if you want to persist it, just call save().

Example:

post.save(); // => POST to '/posts'

isDirty means that the record has local changes that have not yet been saved by the adapter. This includes records that have been created (but not yet saved) or deleted.

Dirty states have three child states:

  • uncommitted: the store has not yet handed off the record to be saved.
  • inFlight: the store has handed off the record to be saved, but the adapter has not yet acknowledged success.
  • invalid: the record has invalid information and cannot be send to the adapter yet.

If you want to make a record clean, try something like this (untested by me):

record.get('stateManager').send('becameClean'); 

Upvotes: 0

user663031
user663031

Reputation:

This is an extension of @Tom Netzband's proposal with a big more sugar.

First, a mixin for adapters:

// mixins/prevent-save-adapter.js
export default Ember.Mixin.create({
  preventSave: false,

  updateRecord(store, type, snapshot) {
    if (!this.get('preventSave')) 
      return this._super(store, type, snapshot);
    this.set('preventSave', false);
    return true;
  }
});

Then one for models:

// mixins/prevent-save-model.js
export default Ember.Mixin.create({
  saveWithoutSave() {
    var modelName = this.constructor.modelName;
    var adapter   = this.adapterFor(modelName);

    adapter . set('preventSave', true);
    return this.save();
  }
});

The post adapter:

// adapters/post.js
export default ApplicationAdapter.extend(PreventSaveAdapter);

And the post model:

// models/post.js
export default DS.Model.extend(PreventSaveModel, {
  ...
);

Using this:

// controllers/some-controller.js
export default Ember.Controller.extend({

  actions: {
    someAction () {
      (...)
      post.saveWithoutSave();
    }
  }
});

Untested.

Upvotes: 3

Related Questions