Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

belongsTo retrieved via "links" attribute cannot be accessed via get() #1443

Closed
abobwhite opened this issue Oct 11, 2013 · 13 comments
Closed

Comments

@abobwhite
Copy link

If I have a model "User" which has a relationship: membership: DS.belongsTo('membership', {async : true}) that is fetched from the links hash in the payload from the server, that membership is correctly fetched and loaded on to the User. That being said, saying user.get('membership') does not return the membership model. Instead, user.get('membership').get('content') is required to actually use the model...this seems like a bug to me. Am I missing something?

@kevinansfield
Copy link
Contributor

I have just run into this issue too. Is this a known change in the API for ember-data 1.0? I haven't seen it mentioned anywhere in the docs.

In my case I wasn't using a "links" hash but an array of IDs.

@wycats
Copy link
Member

wycats commented Oct 18, 2013

In Ember Data 1.0, user.get('membership') on an async relationship returns a Promise, not a shell of a record:

user.get('membership').then(function(membership) {
  // use membership here
});

You can return a promise directly from the model hook in Ember:

App.MembershipRoute = Ember.Route.extend({
  model: function() {
    return this.modelFor('user').get('membership');
  }
});

@wycats wycats closed this as completed Oct 18, 2013
@abobwhite
Copy link
Author

@wycats That is not the issue. The issue is that when the promise resolves, it is not providing the model, but rather that it's providing a construct with requires me to call user.get('membership').get('content') even when the promise has been resolved...I feel like user.get('membership') should just give me the model...

@wycats
Copy link
Member

wycats commented Oct 18, 2013

Are you saying that in here: user.get('membership').then(function(membership) { /* membership is not a model */ })?

@sly7-7
Copy link
Contributor

sly7-7 commented Oct 18, 2013

@wycats In this use case, I think the promise was resolved, so as a user when using a belongsTo, even with async I would like to be able to use user.get('membership') returns the corresponding model.
But I guess that does not matter, because using user.get('membership').then(function(membership) {}) is synchronous when the promise is already resolved ?

@abobwhite Did I correctly understood your expectation ?

@wycats
Copy link
Member

wycats commented Oct 18, 2013

This is actually extremely critical to how the whole thing works:

When you make a relationship async, it will always, 100% of the time return a promise when you get it. Otherwise, code could randomly change between returning a promise and a value based on other, non-local code. That would be disastrous.

A lot of promise-related annoyances will become easier with ES6:

spawn(function*() {
  var memberships = yield this.get('memberships');
  // memberships is the value that would have been passed to .then
});

@wycats
Copy link
Member

wycats commented Oct 18, 2013

Also, for what it's worth, I'm considering making all relationships async, because the current way it works has proven to be somewhat confusing and prone to people hacking at options until they get the behavior they want.

@krisselden
Copy link
Contributor

@abobwhite in user.get('membership').get('content') the content property is an internal implementation detail. The relationship get('membership') uses a proxy for data-binding purposes and content is the target of that proxy when the promise resolves, it isn't meant to be used directly in user code. So while content is a public api of ObjectProxy the fact that an async relationship is a proxy is not a public api, that it is a promise is the public API.

+1 on making it always async. It will be a little annoying for the always embedded case, it is too subtle and leads to other complexity that I think is harder to deal with.

@abobwhite
Copy link
Author

@wycats @kselden Even when in some controller logic if I would like to just use this.get('membership'). I instead have to use this.get('membership').then(function(membership){ /* do things here */}); even though the promise is already resolved...this functionality used to work just fine. But when other improvements were made, this changed. @wycats I understand your reasoning about always returning the promise but it sure makes the use of a relationship a bit wonky when used in javascript (not just in templates). It would be nice to see this handled a bit differently.

@sly7-7 Yes, you understood me correctly.

@kevinansfield
Copy link
Contributor

@wycats This seems to be causing issues with computed properties too, for example in 0.13 I was using this code:

showAttachments: (->
  (@get('viewingSelf') || @get('isFriend')) && @get('user.attachments.length')
).property('user.attachments.@each', 'viewingSelf', 'isFriend')

Which no longer works because @get('user.attachments') is referring to a promise object. How should this type of access to relationships work now?

@ryanirilli
Copy link

I am having the same problem. Even after the record is fully loaded, now that my relationship is async, it becomes a PromiseObject instead of a model instance. I want to be able to call model methods on that object. Am I missing something? At what point does a PromiseObject turn into a materialized model?

update
I ended up doing this

Em.RSVP.all([getModel1, getModel2]).then(function(realModels){
 model1 = realModels[0];
 model2 = realModels[1];
  //call model methods
});

Is this the best way to do this?

@toobulkeh
Copy link

For posterity, whatever happened to "async as default" as discussed above?

@pangratz
Copy link
Member

@toobulkeh relationships are async by default in ember-data since v2.x (if I am not mistaken), see #3366.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants