Skip to content

Instantly share code, notes, and snippets.

@billdami
Last active February 24, 2019 16:57
Show Gist options
  • Save billdami/1b92f2e5f9574f8d15e59ef2651f5b34 to your computer and use it in GitHub Desktop.
Save billdami/1b92f2e5f9574f8d15e59ef2651f5b34 to your computer and use it in GitHub Desktop.
Ember Data - Serializers & Adapters
import RESTAdapter from 'ember-data/adapters/rest';
import { dasherize } from '@ember/string';
import { computed } from '@ember/object';
export default RESTAdapter.extend({
//set the host URL for all requests
host: 'http://example.com',
//modify the base URL path for all requests
namespace: 'api/v1',
//define a `headers` property to send custom HTTP headers for all requests
headers: computed(function() {
return {
'X-Some-Custom-Header': 'foo'
};
}),
//customize the URL path segment that is generated for all models
//by default, RESTAdapter generates paths in the form of `/some_model`
pathForType() {
let pathName = this._super(...arguments);
return dasherize(pathName);
}
});
import Controller from '@ember/controller';
export default Controller.extend({
appName: 'Ember Data - Serializers & Adapters',
actions: {
saveRecord(model) {
return model.save();
}
}
});
import Ember from 'ember';
import { hash } from 'rsvp';
export default Ember.Route.extend({
model() {
return hash({
employees: this.store.findAll('employee'),
meese: this.store.findAll('moose')
});
}
});
import RESTSerializer from 'ember-data/serializers/rest';
export default RESTSerializer.extend({
//all outgoing requests (POST/PUT/DELETE) will invoke this method before being sent
//which allows for abitrary manipulation and customization of the JSON payload
serialize(snapshot, options) {
if(!options) {
options = {};
}
//include the record ID in the request body when saving models
options.includeId = true;
return this._super(snapshot, options);
}
});
<div class="container">
<h2>{{appName}}</h2>
<div class="row mb-5">
<div class="col-12">
<h4>Employees</h4>
<ul>
{{#each model.employees as |employee|}}
<li class="mb-4">
<div class="form-inline">
{{input
value=employee.firstName
class="form-control mr-sm-2 mb-2"
}}
{{input
value=employee.lastName
class="form-control mb-2"
}}
</div>
<div>
{{#each employee.phoneNumbers as |phoneNumber|}}
<div>
{{phoneNumber.number}}
</div>
{{/each}}
</div>
<div>
{{#each employee.tags as |tag|}}
<span class="badge badge-secondary">
{{tag.label}}
</span>
{{/each}}
</div>
<button
type="submit"
class="btn btn-primary mt-2"
{{action "saveRecord" employee}}
>
Save
</button>
</li>
{{/each}}
</ul>
</div>
</div>
<div class="row mb-5">
<div class="col-12">
<h4>Meese</h4>
<ul>
{{#each model.meese as |moose|}}
<li>
{{moose.name}}
</li>
{{/each}}
</ul>
</div>
</div>
</div>
{{outlet}}
import ApplicationAdapter from 'twiddle/application/adapter';
export default ApplicationAdapter.extend({
//customize the URL path name that is generated for the employee model
//e.g. http://example.com/namespace/{the-model-path}
pathForType() {
const path = this._super(...arguments);
return `gavant-${path}`;
}
});
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
//attributes
firstName: attr('string'),
lastName: attr('string'),
//relationships
tags: hasMany('tag'),
phoneNumbers: hasMany('phone-number')
});
import DS from 'ember-data';
import ApplicationSerializer from 'twiddle/application/serializer';
import Inflector from 'ember-inflector';
const inflector = Inflector.inflector;
//add the EmbeddedRecordsMixin to a model serializer
//to enable support for embedded relationships
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
//embedded relationships are defined in the `attrs` object
attrs: {
//the key in this object is the name of the relationship property in the model
//and is set to an object that defines if the relationship should be expected as
//embedded in the JSON when serializing (POST/PUT) payloads
//and/or when deserializing (GET) responses
phoneNumbers: {
//here we are telling ember data to expect full embedded records when
//receiving and deserializing response JSON
deserialize: 'records',
//but when saving and serializing/sending payloads for the model
//to not send the relationship at all
serialize: false
}
},
//override the root key for an outgoing requests (POST/PUT)
//by default this will be the camel-cased model name ("employee")
payloadKeyFromModelName() {
return 'gavantEmployee';
},
//overriding the normalization (deserializing) hook that is called specifically
//only when receiving an array response (e.g. a GET /some-models list)
normalizeArrayResponse(store, primaryModelClass, payload) {
//the root json key for this response data is not standard
//so we intercept the normalization and move the data to where
//ember data is expecting it ("employees")
let rootKey = inflector.pluralize(primaryModelClass.modelName);
payload[rootKey] = payload['gavantians'];
delete payload['gavantians'];
return this._super(...arguments);
},
});
export default function() {
window.server = this;
this.urlPrefix = 'http://example.com';
this.namespace = 'api/v1';
this.get('/gavant-employees', () => {
return {
gavantians: [
{
id: 1,
firstName: "Bill",
lastName: "Dami",
tags: [1, 3],
phoneNumbers: [
{phoneNumberId: 1, phoneNumberFormatted: '(555) 342-9273'},
{phoneNumberId: 6, phoneNumberFormatted: '(555) 645-4362'}
]
}, {
id: 2,
firstName: "Adam",
lastName: "Baker",
tags: [3],
phoneNumbers: [
{phoneNumberId: 2, phoneNumberFormatted: '(555) 942-4324'}
]
}, {
id: 3,
firstName: "Bill",
lastName: "Murray",
tags: [1, 2, 3],
phoneNumbers: [
{phoneNumberId: 3, phoneNumberFormatted: '(555) 732-1235'}
]
}, {
id: 4,
firstName: "Catherine",
lastName: "Brower",
tags: [2, 3],
phoneNumbers: [
{phoneNumberId: 4, phoneNumberFormatted: '(555) 753-2843'}
]
}, {
id: 5,
firstName: "Gabriella",
lastName: "Spain",
tags: [1],
phoneNumbers: [
{phoneNumberId: 5, phoneNumberFormatted: '(555) 212-3346'}
]
}
],
tags: [
{
id: 1,
TAG_LABEL: "Tag #1"
}, {
id: 2,
TAG_LABEL: "Tag #2"
}, {
id: 3,
TAG_LABEL: "Tag #3"
}
]
}
});
this.put('/gavant-employees/:id', (schema, req) => {
const body = JSON.parse(req.requestBody);
return {
employee: body.gavantEmployee
};
});
this.get('/meese', () => {
return {
meese: [
{
id: 1,
name: 'Bullwinkle'
}, {
id: 2,
name: 'Thidwick'
}, {
id: 3,
name: 'Pier'
}
]
}
});
}
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo, hasMany } from 'ember-data/relationships';
import Inflector from 'ember-inflector';
const inflector = Inflector.inflector;
//the english dictionary says that "moose" doesn't have a plural form
//inflector.uncountable('moose');
//but we all know the correct form...
inflector.irregular('moose', 'meese');
export default Model.extend({
name: attr('string')
});
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
number: attr('string')
});
import ApplicationSerializer from 'twiddle/application/serializer';
export default ApplicationSerializer.extend({
//by default, the expected unique primary key for models is "id"
//customize this as needed by defining a `primaryKey`
//however, within your application code, you still access the
//primary key via "id", e.g. "model.id"
primaryKey: 'phoneNumberId',
attrs: {
//keys in the JSON payloads to can be mapped to a different attribute name
//by adding them to this `attrs` object in the form of `attrName: "jsonKeyName"`
//this is the shorthand for, and is equvialent to: `attrName: {key: "jsonKeyName"}`
number: 'phoneNumberFormatted'
}
});
/* add custom css here */
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
//attributes
label: attr('string')
});
import ApplicationSerializer from 'twiddle/application/serializer';
export default ApplicationSerializer.extend({
//define general rules for how all attribute names on the model
//should be converted to/and translated from JSON key values
//the `method` param value refers to if the data is being
//sent ("serialize") or received ("deserialize")
keyForAttribute(attr, method) {
return `TAG_${attr.toUpperCase()}`;
}
});
{
"version": "0.15.1",
"EmberENV": {
"FEATURES": {}
},
"ENV": {
"ember-cli-mirage": {
"enabled": true
}
},
"options": {
"use_pods": true,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js",
"ember": "3.4.3",
"ember-template-compiler": "3.4.3",
"ember-testing": "3.4.3",
"bootstrap": "https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
},
"addons": {
"ember-data": "3.4.2",
"ember-cli-mirage": "0.4.14"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment