1

I'm currently using the FixtureAdapter in my Ember app, but when I switch to the RESTAdapter, my URLs no longer work.

The app is a scorekeeping type thing, and I want users to be able to log all the scores without having to be connected to the Web. After the game is finished they can optionally save all the data to the server.

Now, when Ember wants to route to say, matches/:match_id, the ID isn't there because I didn't commit anything to the server/store, so my models don't yet have an ID and I get URLs like: /match/null/games/null

Is this expected behaviour? And if so, is there a workaround? I thought about using model.clientId and then overriding the model hook for each route to try and fetch the Model from the store using the id when present and falling back to clientId. Any other ideas?

UPDATE March 10, 2013:

The following seems to fit my needs and allows to (for now) forget about moving back and forth between local storage and the REST adapter:

App.Store = DS.Store.extend({
  revision: 11,
  adapter: DS.RESTAdapter.extend({
    namespace: 'api/v1',
    bulkCommit: true,
    generateIdForRecord: function(store, record) {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
      });
    }
  })
});

UUID function taken from: Create GUID / UUID in JavaScript?

Community
  • 1
  • 1
Dave Goulash
  • 125
  • 10

1 Answers1

2

If a record hasn't been committed, then it shouldn't have an id yet. Furthermore, a url that serializes the application state of viewing that record doesn't make any sense because the record won't exist in another browser until it is committed. You couldn't just paste the url elsewhere and have it load where you left off.

I think what you really want to do is serialize the application state differently (ie. generate a less specific url) when the record is uncommitted. You can achieve this by overriding the serialize method in your route.

For example,

App.PostRoute = Ember.Route.extend({
    serialize: function(model, params) {
        if (model && model.get('isNew')) {
            // corresponds to path '/post/:post_id'
            return { post_id: 'new'}
        }

        return this._super(model, params);
    }
});

Now if you call transitionToRoute('post', post) from your controller, where post is a newly created but uncommitted record, the application state will be serialized to the path /post/new. If you pass it a committed record with an id, it will be serialized as usual.

ahmacleod
  • 4,280
  • 19
  • 43
  • Thanks for you feedback! What you are saying makes sense. But would that imply that if you use localStorage for instance, you cannot have unique URLs. It would make sense to be able to bookmark something on an app using localstorage. – Dave Goulash Mar 04 '13 at 07:46
  • That's true; what I've said only applies to `RESTAdapter`. I'm not familiar with `localStorage`, but I'll look into it. – ahmacleod Mar 04 '13 at 07:51
  • I was thinking some more, and I guess this is kind of a theoretical debate on whether local or unpersisted data should have a URL. I think it should, because at the time the object is created (not necessarily persisted) it does exist and thus can be navigated to. So, entering the URL for it should display it as long as the data is there. Back and Fwd buttons should also work. If you refresh the browser and enter the URL again, you will get a 404, which actually makes sense: "resource not found". UUID can really help here I think. – Dave Goulash Mar 04 '13 at 15:04
  • It's a very interesting question. You might want to open a new question phrased that way. – ahmacleod Mar 04 '13 at 15:11
  • I posted a new question here: http://stackoverflow.com/questions/15326308/can-local-or-transient-data-be-represented-by-urls A solution for now would be to persist new data in local storage, so scores can be saved and navigated without having to go to the server for each and every score. Step 2 would be to flush localstorage and persist stuff on the server when the user is ready to do so. – Dave Goulash Mar 10 '13 at 19:09
  • hmm, I just found a valuable piece of info in the emberdata test suite: "Client-side ID Generation: If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer." I'm going to try and subclass the RESTadapater to see if I can maybe have it generate clientside UUIDs that can later be persisted to postgresql. – Dave Goulash Mar 10 '13 at 19:28