What RESTAdapter expects on server responses and what requests should server expect? - django

I'm using Django REST Framework, not Rails (which seems to have several magical gems to make everything work swiftly with Ember) and I've been having some difficulties trying to figure out how Ember expects responses. I'm using Ember CLI, thus I'm also using Ember data.
The documentation states only the typical GET usage, when I'm simply retrieving an object or an array of objects. Documentation states:
The JSON payload should be an object that contains the record inside a root property
And about conventions:
Attribute names in your JSON payload should be the camelCased versions of the attributes in your Ember.js models.
No problem with that.
1. But how should the API respond when there are errors?
Ok, so documentation also states you could use ajaxError to check jqXHR status for an error and then return a populated DS.Error for the record. However, how should I return different kind of errors. For example, let's say the user session is now invalid and because of that the server couldn't delete a record as requested.
2. How will Ember submit requests?
I'm quite new to REST in general. I think Ember simply use the appropriate verb for the action it wants: GET, POST, PUT, DELETE. I think it's quite clear it will send all the model's field to POST a new one, but how about DELETE? Will Ember send all the record or just the ID to delete an object?

Generally you should be able to see the requests Ember makes by just opening your browser dev tools and seeing the network requests.
Ember data likes the api to respond with an errors hash, something like this:
{"errors":{"title":["can't be blank"]}}
Then as long as you define a function to handle the error case:
Ember.Controller.extend({
actions: {
deleteUser: function() {
var user = this.model;
function success() {
// do something cool?
}
function failure() {
user.rollback();
}
user.destroyRecord().then(success, failure);
}
}
});
then user.errors will be automatically populated and you can do an if user.errors in your template.

Related

ember: using cookies with ember-network

Can cookies be used with ember-network requests? Thanks to this answer I know that they can be used with ember-data API requests, but I need to do a network request in an initializer and it doesn't appear the ember-data store can be accessed that early.
Background:
I'm wanting to persist shopping cart data to the backend for these reasons
The ember-cart addon has a smart way of persisting the cart by jsonifying and data model and dumping to localstore when it changes:
window.localStorage.setItem('cart', JSON.stringify(this.payload()));
then upon return visit parsing the json and pushing it into the store in an instance initializer:
...
payload = JSON.parse(payload);
...
cart.pushPayload(payload);
I'd like to do basically the same thing, but instead of getting the JSON from localstorage, get it from the API via the network.
the store ins't available in an initializer, but ember-network is. So hypothetically I think I can do this. The problem I'm running into is that the cookie isn't being passed.
I get around this with ember-data by using this:
xhrFields: {
withCredentials: true
}
in the application adapter, but I can't find any info about whether there's a similar setting for ember-network. I see the request to my API being made in the initializer, but the api doesn't return anything because the browser cookie isn't included.
The fetch API provides a credentials option..
This is also documented at the whatwg-fetch library used by ember-network.
So basically you can do
fetch("/foobar", { credentials:"include" }).then(...)

Google Analytics ID stored in cookie is undefined

We are installing google analytics via Google Tag Manager.
We have custom variable that supposed to take the GA customer id, and send it to our GA.
The variable is defined as follows:
function() {
try {
var cookie = {{GA_ID_Cookie}}.split(".");
return cookie[2] + "." + cookie[3];
} catch(e) {
return 'N/A';
}
}
While {{GA_ID_Cookie}} is a first party cookie variable named "_ga".
In most cases, this values works, but there are some cases where GA_ID_Cookie is undefined (and exception is thrown).
It happens in all browsers. There enough users with "N/A", so its not about cookies disabled issue.
The GTM installs the GA on page view event; It uses this problematic variable as a custom dimension.
My question is how come the ga id is null, and how can we overcome this problem and get the id in other ways.
It is likely that your tag is fired before the cookie is generated.
Try to change the page view to window load. Clear the cookie and retry, it should work.
Like Ashley pointed out you might be facing a race condition whereby you try to access the cookie before it is set by GA.
Please note that the GA cookie ID contains some uninteresting info from the point of view of identifying users, namely the version which should be removed.
If your GA cookie looks like this:
_ga=GA1.2.1033501218.1368477899;
Then the part you're interested in is:
1033501218.1368477899
To retrieve the client ID via the browser, the official way is as follows:
https://developers.google.com/analytics/devguides/collection/analyticsjs/accessing-trackers
// Initializing the `ga` command queue so that commands
// can be queued even if the GA snippet is not loaded
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
// Queuing a command to retrieve the Client ID when the tracker is ready
ga(function(tracker) {
// Logs the client ID for the current user.
console.log(tracker.get('clientId'));
});
If you are using GTM then you need to create a task:
https://www.simoahava.com/analytics/13-useful-custom-dimensions-for-google-analytics/#13-client-id
function() {
return function(model) {
return model.get('clientId');
};
}
If you want to retrieve the Client ID via the server, then you simply need to parse the cookie HTTP header (below example is from request to stackoverflow website) using an HTTP library of your choice and getting rid of the leading GA\d\.\d\. pattern which represents the cookie version.
cookie: prov=f67bae3b-f99c-2f22-84fc-7c2a62862f3d; _ga=GA1.2.1380536973.1571212618; ...

Fetching data from the store in controller

i have a getrank button which is supposed to make get request to the server
So for this i wrote a Getrank function in controller inside which i have this
var self = this;
this.store.find('post',"1").then(function(data){
self.set('mydata',data);
console.log(self.get('mydata'));
},
function(error){
alert(error);
})
It returns a class.,instead i need a json to work on
Is it a normal behaviour or am i doing something wrong?
If you need a JSON response use jQuery's getJSON method. Ember-Data gives you client side records that it manages with a plethora of additional functionality.
Ember and Ember Data are two different products and Ember works just fine without Ember-Data using POJOs

EmberJS and WebSocket | Best Approach?

I have a again which I can't answer for my self properly, maybe because of my lack in expierience with EmberJS.
I have to develop a management interface in EmberJS, using Symfony 2 for the backend, which should act and feel like a desktop application. So far so good, but since alot of people will work with the data inside this application, i would really like to use a WebSocket adapter implementation for EmberJS, since every connected client should always know about changes in entities immediately (or asap). I could write a WebSocket adapter for EmberJS but my problem here is that the WebSocket will do much more then RESTful operations, also the server will send messages without any EmberJS request (e.g. an entity changed and the server broadcasting this change to all clients). That means that i need a "command" structure on top of RESTful operations which, as far as my expierience goes, will not work with a pure DS Adapter.
For example:
Maybe i will trigger a controller method that will send a websocket message like this:
{command: "say", parameters: {message: "Hello guys!"} }
This command is not Entity (DS) related and will never go into the application store.
Another example would be like this:
{command: "load entity", parameters: {type: "Vendor\Bundle\Entity\Type", id: 43} }
Which would load an entity which should be stored in the application store.
Well, as i said, im not that familiar with EmberJS that I could figure out which the best approach could be. Should I bypass the DS Adapter completely and check for "isDirty" and just the push methods after loading entities? I'm happy about any idea you have!
As far as I understand your question, you want to push changes from your backend to your single page app?
You can push custom JSON into your application's store in Ember by using self.store.push('modelName', json). Have a look at the docs for a better undestanding.
So for example if your server sends you JSON via websocket that looks like this
{
- "message": {
"type": "fooModel",
"data": {
... // Model attributes here
}
}
}
you can push the data into your store. The following snippet would work with SocketIO for example:
App.ApplicationRoute = Ember.Route.extend({
activate: function() {
// connect to the websocket once we enter the application route
var socket = window.io.connect('http://localhost:8080');
var self = this;
socket.on('message', function(data){
self.store.push(data.type, data.item);
});
}
});
You can easily modify this snippet to fit your needs.

Calling findAll during route transition

I'm using Ember 1.4 with EmberData beta 7. The routes in my application are fairly straight forward and looks like this. ScenarioController and StratsControllers are ArrayControllers. StratsStratController is an ObjectController.
App.Router.map(function () {
this.route('scenarios', {path: "/scenarios"});
this.resource('strats', {path: "/"}, function() {
this.route('strat', {path: "/strat/:strat_id"});
});
});
When I first transitioned into the 'strats' route, Ember calls the findAll method, which makes a request to my server for all 'strat' instances as expected. My server returns all data associated with the 'strat' model, side loading all related hasMany records. Then I transitioned to the scenarios route, and Ember calls findAll to fetch all 'scenario' instances, which was also as expected. However, when I transitioned back to the 'strats' route via the browser's back button, I see another GET message from Ember to my server requesting all 'strat' instances again. This surprised me. Why did Ember make another call to findAll for the 'strat' instances when it already has it in DS.store? Is this expected behavior?
I think its because its a live array of data, so ember checks to see if anything has changed in the mean time. You can change the data to a static array using the toArray() method but the way it is currently means that any updates to the database are automatically reflected on the client.
I have just come across this in the docs:
FINDING ALL RECORDS OF A TYPE
1
var posts = this.store.find('post'); // => GET /posts
To get a list of records already loaded into the store, without making another network request, use all instead.
1
var posts = this.store.all('post'); // => no network request
find returns a DS.PromiseArray that fulfills to a DS.RecordArray and all directly returns a DS.RecordArray.
It's important to note that DS.RecordArray is not a JavaScript array. It is an object that implements Ember.Enumerable. This is important because, for example, if you want to retrieve records by index, the [] notation will not work--you'll have to use objectAt(index) instead.