getoutreach / epf

A framework for keeping your Ember.js apps in sync.
http://epf.io
MIT License
368 stars 33 forks source link

inject models from known json #18

Closed heartsentwined closed 11 years ago

heartsentwined commented 11 years ago

Use case: pre-load static model data from embedded json in js files.

Ember-data version

class App.Store extends DS.Store
  init: ->
    super.apply this, arguments
    @loadMany(App.Foo, '[{"id":1, "value":"a"}, {"id":2, "value":"b"}]')

Epf equivalent = ?

heartsentwined commented 11 years ago

I saw session.merge(), but I'm not sure if that's the equivalent. The method signature

  /**
    @param {Ep.Model} model The model to merge
    @param {Ep.MergeStrategy} [strategy] The merge strategy to use
  */

seems to expect a model instance. Unless the epf idiom is to create each individual models from the json manually, and then load them?

ghempton commented 11 years ago

In epf, unlike ED, you can actually freely create models using normal create. In the above case you could simply do:

session.merge(App.Foo.create({"id":1, "value":"a"}));

In our app, we actually preload models serialized by AMS (which may contain sideloads etc.). In this case you have to go through the adapter. Eventually I want to add a cleaner api around this.

heartsentwined commented 11 years ago

We have the same AMS use case too, the original code was actually

class App.Store extends DS.Store
  init: ->
    super.apply this, arguments
    @loadMany(App.Foo, \
    <%= ActiveModel::ArraySerializer.new(Foo.all).as_json.to_json %>)

but I have stripped out that part for being not an epf concern.

Would you mind posting your epf example for this?

heartsentwined commented 11 years ago

One more question:

What would be the state of the new model if I do this?

session.merge(App.Foo.create({"id":1, "value":"a"}));

- or in other words, if I flush() the session afterwards, would it try to save a "new" model to the server?

ghempton commented 11 years ago

I am actually surprised that works for you. Last I checked you had to go through the adapter in ED as well to accomplish this.

Here is a stripped down version of our code:

# Preload models
App.initializer
  name: 'preload_models'

  initialize: (container, application) ->
    adapter = container.lookup('adapter:main')
    session = container.lookup('session:main')
    models = adapter.didReceiveDataForFind(ENV['preload'], type)
    models.forEach (model) -> session.merge(model)

Could be prettier :/

ghempton commented 11 years ago

Re: your second question: merge is only meant to merge in new data that has come from the server. In the above case it would not go to the server.

ghempton commented 11 years ago

btw @heartsentwined , feel free to add me ghempton@gmail.com if you ever want to IM.

heartsentwined commented 11 years ago

Thanks for the sample, so it's

adapter.didReceiveDataForFind('[{"id":1, "value":"a"}, {"id":2, "value":"b"}]', App.Foo)
# first arg json string
# second arg model class

right?

ghempton commented 11 years ago

Ah it actually expects only a single serialized model, not an array. For now I think you will have to iterate over the array. E.g.

[{"id":1, "value":"a"}, {"id":2, "value":"b"}]'.forEach (json) -> adapter.didReceiveDataForFind(json, App.Foo)
ghempton commented 11 years ago

Actually nm, I take that back :P. It should work with an array. Sorry about the confusion.

heartsentwined commented 11 years ago

Thanks a lot for the clarifications! I'll test that out and reopen this if it doesn't work.

- and thanks for the IM invite too!

heartsentwined commented 11 years ago

Gotcha for anyone coming across this usecase: the above code sample does not work - I have to wrap the json in its root key.

json = '[{"id":1, "value":"a"}, {"id":2, "value":"b"}]'
adapter.didReceiveDataForFind(json, App.Foo) // no

json = '{ foos: [{"id":1, "value":"a"}, {"id":2, "value":"b"}] }'
adapter.didReceiveDataForFind(json, App.Foo) // okay now