Search code examples
ember.jslocal-storageember-data

Ember localstorage adapter has different data when I refresh


I'm relatively new to Ember and have been struggling to build a simple CRUD app for learning purposes. I'm using localstorage-adapter to mock the backend. I'm having a horribly bad time debugging because Ember Inspector shows different data on different pages.

Right now I have full CRUD functionality except for updating. Say I create a new Song (S1) that's a part of an album (A1). I can change S1 to belong to another album (A2), and that saves and persists in local storage even if I refresh.

Now, if I decide I want to change S1's album back to A1, it'll save and display on the show page, but if I refresh, the album reverts to A2. If I go to the edit page, S1's album is listed as A2. If I refresh on the edit page, it changes to A1, but even if I click save it'll show A1 on the show page but if I refresh or go back to edit it goes back to A2... I find this especially weird because it did save properly (and persisted with page reloading) on the initial edit attempt. It's subsequent edit attempts that it doesn't save properly.

A song has a title and belongs to an album.

Songs Controller

import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    updateValue(value) {
      this.set('model.song.newAlbum', value)
    },
    updateSong(model) {
      this.store.findRecord('song', model.get('id'))
        .then(song => {
          if (song.get('newAlbum')) {
            this.store.findRecord('album', song.get('newAlbum'))
              .then(album => {
                song.set('album', album);
                album.save();
              })
          }
        song.save();
      })
      .then(() => this.transitionToRoute('songs.show', model.get('id')));
    }
  }
});

Solution

  • To make sure the data persists properly on the back end (which is the local storage in this project), you'll need to do a bit more management of the relationships.

    You'll need to:

    1. Set the new album as the song's album property - song.set('album', newAlbum)
    2. Save the song's old album if there was one to remove the song from oldAlbum.songs
    3. Save the song: persist the song.album property to the back end
    4. Save the song's new album: persist the updated newAlbum.songs to the back end

    In addition, I've used RSVP Hash to return multiple models so you don't have to fetch the song data object in your function (it's resolved and passed in to the model for you)

    import Ember from 'ember';
    
    export default Ember.Route.extend({
      model(params) {
        return Ember.RSVP.hash({
          song: this.store.findRecord('song', params.song_id),
          albums: this.store.findAll('album')
        })
      },
      actions: {
        updateSong(song) {
          if (song.get('newAlbum')) {
            //  Get the current album's Ember object as 'oldAlbum'
            song.get('album').then((oldAlbum) => {
              // Then get the new album's Ember object as 'newAlbum'
              this.store.findRecord('album', song.get('newAlbum')).then(newAlbum => {
                // Set the song's album to the new album
                song.set('album', newAlbum);
                if (oldAlbum) {
                  // Save the old album if it exists
                  oldAlbum.save();
                }
                // Save the new album
                newAlbum.save();
                // Save the song
                song.save().then(() => {
                  // Then transition to new route
                  this.transitionTo('songs.show', song.get('id'))
                })
              })
            });
          }
        }
      }
    });
    

    Finally, just a heads up that the push that sets up your initial entities in your routes/application.js only pushes to the cache and not the local storage. With those there, you will always see Go Go Go associated with What Is Life -- don't let it throw you off.

    Also, remember you can cut and paste the local storage contents out of your developer tools to help debug what's in there vs. the Ember cache.