psr7-demo icon indicating copy to clipboard operation
psr7-demo copied to clipboard

Empty embedded models

Open neverfox opened this issue 10 years ago • 6 comments

I just ran into a situation where I have an embedded model that only sometimes has data in Firebase (i.e. it's optional). Then when the parent model is resolved in Ember and it lacks the data, there is no FP.model instance there, just null. As a result, attempts to bind to the embedded schema properties (e.g. because you want to populate those fields) result in nothing happening. For example:

Note = FP.Model.extend
  content: attr "string", default: ""
  author:  attr "string", default: ""

Thing = FP.Model.extend
  name: attr "string"
  note: hasOne "note"

Now, given some data in Firebase (which I'll just represent as JSON here), taking advantage of the schema-less nature to avoid storing unnecessary data:

[{
  "name": "Foo"
},
{
  "name": "Bar",
  "note": {
    "content": "Lorem",
    "author": "Twain"
  }
}]

The model instance for "Foo" in Ember, rather than containing an FP.model in the note slot, with default values (or undefined, if I can left out the defaults), returns just a simple null. I would think that the model tree should fully reflect the schema so that you can immediately start binding to such properties and change them (or even display their default values).

neverfox avatar Jun 17 '14 04:06 neverfox

It's possible to set a default value for the association, something like:

Thing = FP.Model.extend
  note: hasOne default: -> @store.createRecord("note")

I think it's better to make this explicit, as otherwise computed property checks would fail unexpectedly:

Thing = FP.Model.extend
  note: hasOne()
  hasNote: Ember.computed.bool("note") # never false if note was implicitly defaulted

Maybe there could be some syntactic sugar to setup a default has one association, something like:

Thing = FP.Model.extend
  note: hasOne(default: true)

rlivsey avatar Jun 17 '14 10:06 rlivsey

That seems like the perfect thing (and I like the idea of the syntactic sugar too), but when I tried it, the default function I set up is never called (the source doesn't call getDefaultValue when setting up a hasOne). Perhaps I mistook a suggestion of functionality for something that already exists?

neverfox avatar Jun 17 '14 22:06 neverfox

Hmm it should work, I'm using it in my app but maybe there's something different about how I've got it setup.

It's getting late here so I'm going to call it a night, but I'll have a dig into it tomorrow and see if I can figure out what's going on.

rlivsey avatar Jun 17 '14 23:06 rlivsey

Thanks for looking into it.

neverfox avatar Jun 17 '14 23:06 neverfox

Sorry to bother you, but I was wondering if you got a chance to look at your setup.

neverfox avatar Jun 25 '14 05:06 neverfox

Also, I noticed some strange behavior. My thing has a note, as you've seen, but also has a hasMany called stuff, and each one of those models can also have an optional note. If I do a toFirebaseJSON, when none of the models have notes, the note property doesn't appear on the "thing" level, but appears as note: null on each item in stuff. When I fork the store, I get the exact opposite outcome: note: null on thing, not no note property at all on any item in stuff.

neverfox avatar Jun 25 '14 05:06 neverfox