Reloading data after commiting store is impossible #553

Closed
darthdeus opened this Issue Dec 26, 2012 · 16 comments

Comments

Projects
None yet
3 participants
Member

darthdeus commented Dec 26, 2012

This is partially related to #545

Basically the issue is when I change some model, and I know it affects data in another one, so I need to reload it from the server. For example like this:

App.store.createRecord(App.Bracket, { tournament_id: tournament.id });
App.store.commit();
tournament.reload();

In this example, I know that creating a new App.Bracket will result in some intensive server side computation, which results in changes to the App.Tournament model. To be more specific, I have a hasMany relation which looks like this

App.Tournament = DS.Model.extend({
  rounds: DS.hasMany("App.Round")
});

but there is no way for me to get the round ids other than reloading all of the data from the server.

One might say that I should just make it a part of the App.Tournament model and do it as an update, but the App.Bracket is really a thing of it's own, and I'm not sure if doing something like hasBracket: DS.attr("boolean") and save that to force a PUT request to the server would be a semantically good solution.

This goes hand in hand with the issue that there is no good way to either specify a custom request path, such as POST /tournaments/1/generate_bracket for such things, which could be called as a method, but would result in reloading the model.

Of course we can put all of the logic under PUT /tournaments/1, but that means the server side would have to do a lot of pattern matching based on what attributes changed. Not to mention that you would have to know what to change when on the client to trigger the right action.

Member

tchak commented Dec 26, 2012

you should return "sideload" data with tournament and rounds in bracket create request

{
  "bracket": {"id": 1, "tournament_id": 1},
  "tournaments": [{"id": 1, "rounds": [1,2,3]}],
  "rounds": [{"id": 1}, {"id": 2}, {"id": 3}]
}
Member

darthdeus commented Dec 26, 2012

@tchak Thanks this really works. However I still think the issue should remain open, because if I understand this correctly, it only works for relations.

For example if I have a currentUser who has something like participationCount which is a property aggregated on the server from some data. Let's say that it is more complex than just doing currentUser.get("tournaments.length").

In that case I might still want to reload the currentUser after I do a request which could affect that value, but I would want to do that synchronously after commiting the store.

Member

tchak commented Dec 26, 2012

Well, then you should return the user alongside transaction. You can return in sideloading data what ever you want. You may need to define a mapping in the adapter in case returned data is not associated to the root record.

As for general reloading support see my comment in #546

Member

darthdeus commented Dec 26, 2012

@tchak But the data is not always related. It might be just a pre-computed property which is cached on the server.

For example if you think about reputation on stackoverflow, you wouldn't specify it as a relation to all of the different sources of the reputation, but rather as a plain number which is fetched from the server.

But you would still want to reload it when a user does something which changes it, because you know that action has an effect on it.

Member

tchak commented Dec 26, 2012

I never said there have to be a relationship. Example, user is not related to the root record.

{
  "bracket": {"id": 1, "tournament_id": 1},
  "tournaments": [{"id": 1, "rounds": [1,2,3]}],
  "rounds": [{"id": 1}, {"id": 2}, {"id": 3}],
  "user": {"id": 1, "count": 3}
}

It is exactly the same as doing a reload, except you do 1 request instead of 2 :)

Member

darthdeus commented Dec 26, 2012

Either one of us is wrong, or we found a bug :) If I return what you said, or specifically

"users": [ {"id": 1, "count": 3} ]

it will update the user, but I will get this error at the same time.

assertion failed: Your server returned a hash with the key users but you have no mappings

Which I guess shouldn't happen if the record is being updated.

Member

darthdeus commented Dec 26, 2012

Also if I try to sideload in DELETE /brackets/1 and return data for a tournament like this

{
  "tournaments": [{"id": 1, "rounds": [1,2,3]}]
}

I'm getting

Object #<Object> has no method 'eachAssociation' 

but the tournament model is also being updated. Maybe sideloading is broken?

Member

tchak commented Dec 26, 2012

this is what I ment by adding a mapping to your adapter :

App.Adapter.reopen({
  mappings: {users: 'App.User'}
});
Member

tchak commented Dec 26, 2012

Hmm as for sideloading without root data it is possible it is broken... I will check

Member

darthdeus commented Dec 26, 2012

Aren't those mappings supposed to be resolved automatically from the class name?

Member

tchak commented Dec 26, 2012

Except for non related data you do not have a class name :) This is why in case of non related data you need mappings.

Member

darthdeus commented Dec 26, 2012

It is not documented anywhere :(

Anyway, it seems to be working with the mappings for the POST /brackets, but DELETE /brackets/1 is still failing with

Object #<Object> has no method 'eachAssociation' 

I guess the mappings are working, but this another issue.

Member

tchak commented Dec 26, 2012

@darthdeus could you post a full stack trace?

Member

tchak commented Dec 26, 2012

And yes, sideloading mappings should be documented, and configuration maybe should be moved to adapter.map api...

Member

darthdeus commented Dec 28, 2012

@tchak Here's the stack trace

Uncaught TypeError: Object #<Object> has no method 'eachAssociation' ember-data-local.js:6340
DS.RESTAdapter.DS.Adapter.extend.didSaveRecord ember-data-local.js:6340
DS.RESTAdapter.DS.Adapter.extend.didDeleteRecord ember-data-local.js:6472
(anonymous function) ember-data-local.js:6464
(anonymous function) ember-local.js:3861
Ember.handleErrors ember-local.js:380
invoke ember-local.js:3859
Ember.run ember-local.js:4048
ajax.success ember-data-local.js:6463
fire jquery.js:1076
self.fireWith jquery.js:1194
done jquery.js:7539
callback

the line numbers might be off by a couple of lines in ember-data.

Member

darthdeus commented Jan 1, 2013

I'm not having the same issue with the current master, so I guess we can close this due to the refactoring on embedded records branch?

/cc @tchak

wagenet closed this Jan 9, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment