Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rainy Day Ember Data

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Rainy Day Ember Data

Demos are great at teaching us the basics of working with a framework. However, what are you "todo" when your app is faced with an API that doesn't play along? In this talk, I'll be discussing the Ember Data workarounds I've discovered while building a non-trivial Ember application.

Avatar for Tony Schneider

Tony Schneider

March 30, 2014
Tweet

More Decks by Tony Schneider

Other Decks in Programming

Transcript

  1. – RTFM “An adapter is an object that receives requests

    from a store and translates them into the appropriate action to take against your persistence layer.”
  2. 1 App.ApplicationAdapter = DS.ActiveModelAdapter.extend({! 2 ! 3 host: 'https://jedimingle.com',! 4

    ! 5 namespace: '/api',! 6 ! 7 headers: function() {! 8 return {! 9 "AUTHORIZATION": "Bearer" + this.get("blueprints.accessToken")! 10 };! 11 }.property("blueprints.accessToken")! 12 ! 13 });
  3. 1 App.JediKnightAdapter = App.ApplicationAdapter.extend({! 2 ! 3 pathForType: function() {!

    4 var dasherized = Ember.String.dasherize(type);! 5 return Ember.String.pluralize(dasherized);! 6 }! 7 ! 8 });! 9 ! 10 // We can now do the following! 11 //! 12 jedi.save(); // POST /jedi-knights
  4. In Ember Data a Serializer is used to serialize records

    when they are transferred out of the store.
  5. 1 App.Cantina = DS.Model.extend({ ... });! 2 ! 3 App.CantinaSerializer

    = DS.RESTSerializer.extend({! 4 ! 5 serializeIntoHash: function(hash, type, record, options) {! 6 hash.store = this.serialize(record, options);! 7 },! 8 ! 9 serialize: function(record, options) {! 10 var json = this._super(record, options);! 11 ! 12 json.weaponPolicy = json.lightSaberPolicy;! 13 delete json.lightSaberPolicy;! 14 ! 15 return json;! 16 }! 17 ! 18 }); Notice no return
  6. In Ember Data a Normalizer is used to transform API

    payloads into objects suitable for the store.
  7. Normalization Flow Called in all cases.! Good for removing extra

    data ! from payload. Store’s meta data for specific ! type. Good for top level! restructuring into ember! data types. General purpose, across all keys Normalizing specific to! part of the payload
  8. Restructure and Normalize 1 // {! 2 // jedis: [{!

    3 // id: 10, name: "Luke Skywalker", mitochlorian_count: 937,! 4 // lightsabers: [! 5 // { lightsaber_id: 5, color: "blue" },! 6 // { lightsaber_id: 6, color: "green" }! 7 // ]! 8 // }]! 9 // }
  9. 1 App.JediSerializer = DS.ActiveModelSerializer.extend({! 2 ! 3 extractSingle: function(store, primaryType,

    payload, id, requestType) {! 4 var lightsabers = payload.lightsabers;! 5 var jedi = payload.jedis[0];! 6 ! 7 jedi.lightsaber_ids = lightsabers.map(function(saber) {! 8 return saber.lightsaber_id;! 9 });! 10 ! 11 delete(payload.lightsabers);! 12 delete(payload.jedis);! 13 ! 14 payload = { jedi: jedi, lightsabers: lightsabers };! 15 return this._super(store, primaryType, payload, id, requestType);! 16 },! 17 ! 18 normalizeHash: {! 19 lightsabers: function(hash) {! 20 hash.id = hash.lightsaber_id;! 21 delete(hash.lightsaber_id);! 22 return hash;! 23 }! 24 }! 25 });
  10. A Small Confession So I lied a little bit… there’s

    no “Normalizer”. The Serializer does both normalization (into) and serialization (out of) the store. But it helped with my mental model. DS.Serializer
  11. – RTFM “The DS.Transform class is used to serialize and

    deserialize model attributes when they are saved or loaded from an adapter.”
  12. Complex Properties // GET /jedis/1! // {! // jedi: {!

    // id: 1,! // name: "Luke Skywalker",! // lightSabers: [{color: "blue", dps: 100}, {color: "green", dps: 250}]! // }! // }! Ruh roh
  13. 1 Ember.Application.initializer({! 2 name: 'customTransforms',! 3 initialize: function(container, application) {!

    4 application.register('transform:objectArray', App.ObjectArrayTransform);! 5 }! 6 });! 7 ! 8 App.ObjectArrayTransform = DS.Transform.extend({! 9 ! 10 serialize: function(objectArray) {! 11 return JSON.stringify(objectArray.get('content'));! 12 },! 13 ! 14 deserialize: function(json) {! 15 if (!Ember.isArray(json)) throw "invalid object array";! 16 if (Ember.isNone(json)) json = [];! 17 var sizes = json.map(function(obj) { return Em.Object.create(obj); });! 18 return Em.ArrayProxy.create({ content: sizes });! 19 }! 20 });! 21
  14. App.Jedi = DS.Model.extend({! ! name: DS.attr("string"),! lightSabers: DS.attr("objectArray"),! ! totalDps:

    function() {! var lightSabers = this.get('lightSabers');! if (!lightSabers) return 0;! return lightSabers.reduce(function(sum, size) {! return sum + size.get("dps");! }, 0);! }.property(“[email protected]")! ! });! It’s an ember data object, bind away!