knownasilya / ember-plupload

Ember component for handling uploads using plupload
MIT License
87 stars 53 forks source link

Provide example for uploading to an ActiveModelAdapter-API #42

Open Awem opened 8 years ago

Awem commented 8 years ago

Ember is often used on top of a data API (e.g. a Rails server). If you want to save data to the API, you update your model on the client side and save() it. A post request is then send to the API connected via e.g. ActiveModelAdapter. I am not sure how to approach this with the plupload workflow of file-read/upload -> model.save. I can do this to save an image to my API:

const picture = this.store.createRecord('picture', {});
file.read().then((url) => {
  if (get(picture, 'url') == null) {
    set(picture, 'url', url);
  }
  picture.save().then(...deal with response...)
});

So the uploading part is happening after save and the upload url is provided by the application adapter. Thus, I can't use upload progress etc. Do you have any preferred appoach to this?

tim-evans commented 8 years ago

I did the following:

const picture = this.store.createRecord('picture', {
  file: file
});
file.read().then(function (dataUrl) {
  if (get(picture, 'url') == null) {
    set(picture, 'url', url);
  }
});

return file.upload('/picture/upload').then(function (response) {
   picture.set('url', response.headers.Location);
   picture.set('file', null);
   return picture.save();
});

Setting the file object on the picture allows for progress to be shown while the file is still being uploaded. Once the file is uploaded, the url can be set to the one provided by the server and it the file can be removed as a temporary variable.

Awem commented 8 years ago

Yeah, I guess there is not really an easy way to integrate this fully with Ember Data. If one wanted to achieve this, upload() would need the option to handle a store method instead of an URL. It would look somehow like this: file.upload(null, picture.save()). Then upload() would monitor the progress of picture.save(). This would need a lot of refactoring, though. Maybe not really worth it... I ended up keeping it simple:

uploadPicture(file) {
  file.upload({
    url: /* your url*/,
    headers: {
      // authorize against backend here
    }
  }).then(
    (success) => {
      const picture = this.get('mainStore').findRecord(
        'picture',
        success.body.picture.id
      ); //optional
    },
    (failure) => {
      file.destroy();
      //...
    }
  );
},

This works fine, because everything is handled at the Rails API. If you upload to url, the Rails sever will create a picture model and serialize it. No need for create and save. If you need the model afterwards, just fetch it by getting the serialized data. But this is optinal (as indicated above). I guess this is more or less the way to go with an API. What do you thing? Feel free to close this issue, if you think it has been discussed enough.

tim-evans commented 8 years ago

Hmm. This seems like it may be nice to bake this into the addon in some way? I feel that I don't have a clear idea of what common patterns could be extracted out at the moment.