Advanced Topics

This guide covers some topics which are relevant to the overview of FW apps, but may not impact all users. A lot of these are exceptions to one of the rules stated in the overview.

Client side

Route setup controller

Not every app overrides the setupController() method, but it is strongly encouraged to override it. By default, Ember sets the results of the model function above as a variable in the controller named model. However, that does not make it clear whether the results are a single model or an array of models, nor what the model type is for this route.

Overriding this method allows renaming this property based on the model type. Suppose we have the following model:

model() {
    return this.store.findAll('user');
}

We can define setupController() as follows:

setupController(controller, model) {
    controller.set('users', model);
}

This will name the users array users in the controller instead of model, making it a lot more clear in the code what the variable references.

Suppose multiple models are returned using a hash, like in the following code:

model() {
    return RSVP.hash({
        services: this.store.query('service', {all: true}),
        categories: this.store.findAll('category'),
        users: this.store.findAll('user')
    });
}

You can define setupController() as follows:

setupController(controller, model) {
    controller.setProperties(model);
}

The result will be each property in the hash will be set as its only variable. This means instead of calling this.get('model.users') to get the users array, you can just use this.get('users').

In addition to making the code cleaner, this approach has a second advantage: if we wanted to switch from returning just users to returning the three models, and we did not override setupController(), we would have to modify every reference to model in the controller to reference model.users instead. With this approach, we only need to modify setupController() to add in the new model properties.

AJAX requests

While most requests made to the server are handled through a model, such as finding all existing models, saving a model, and deleting a model, it is possible to create custom requests using Ember AJAX. For most app requests you are required to inject both the ajax and FW’s config services.

The basic syntax for an ajax request is as follows:

// Gets the URL for an app request from ember-fw
let url = this.get('config').formUrl('example', 'action');
// Uses Ember AJAX to send the request
this.get('ajax').post(url, {
    data: {
        foo: 'bar'
    }
}).then((data) => {
    // handle data
});

This will perform a POST request with a payload of {"foo": "bar"} to the action route of the example controller. The server side is required to define this as a custom route, which is described in Conceptual Introduction - Server.

You are able to use the Ajax service to perform any HTTP-verb request type: put(), post(), delete(), or request() (which is for the GET verb). The data object in options for put and post methods on the Ajax service will be put into the payload (thus in the $object variable on serverside), and the data object in options for request will pass it through as query parameters (thus found in the $options variable). The delete will not allow data to be passed to the server other than that which is in the URL already.

Note that the call to request() (or any other HTTP-verbed method) returns a promise, so code relying on its response typically should use a then() handler like in the above example.

Server side

PATCH verb

The way FW implements PUT is not exactly the same as the standard for PUT. To explain why, it is necessary to mention an HTTP method we do not implement: PATCH. In servers that support PATCH requests, a PUT request means a full replacement for the specified data while PATCH request modifies just part of the data. Due to limited support for PATCH in frameworks and web browsers, FW uses PUT for both request types.

More specifically: In most model calls, notably the ones made by Ember, the entire contents of the model are sent to the server by Ember as expected for PUT. However, with how our API is implemented, if you sent partial data over only the data you sent would be modified; any keys you do not set would remain unchanged. Since the expected behavior here is undefined for PUT, it made sense to implement behavior similar to PATCH to give that functionality without needing to add the extra keyword.

Database

Model fragments

One final type of relationship worth mentioning is fragments. Unlike other relationships, fragments do not have an ID column, instead they use a combination of keys, including a foreign key, as their primary key. Fragments are not intended to be used independently, they instead are fetched alongside another model. The most common use of a fragment is to allow a model to have an array of values as a property; sometimes this is done using a full model as the property, but that makes saving and loading data more difficult. Another use of a fragment is to have optional pieces of a model in case parts of the model are optional together.

A “one to one” fragment is stored in the database by having a foreign key double as the primary key. For “one to many” fragments, the primary key is set to a combination of the foreign key and a value that is expected to be unique. On the client side, fragments are handled using Ember Data Model Fragments which adds both fragment and fragmentArray as functions, similar to belongsTo and hasMany.

One example of a fragment is the currency values in Point of Sales. Rather than hardcode all available coins, the administrator can define them as a property of the account. The primary key of currency is a combination of the account ID and the currency value, as it does not make sense to have two currencies with the same value. Another example of a fragment is in Service Stats for history entry values. The number values use a combination of an entry ID and a field ID, both foreign keys, as the primary key.

Group Control

Technically Group Control is integrated at all three of these levels with the apps because all of our apps currently are all Group Control Dependent apps. This means that a lot of the aspects of Group Control are used over all of the apps, and so in developing you need to have a general understanding of how an app is actually dependent on Group Control. The details about Group Control Integration, especially on the client side, can be found in Ember FW GC's documentation, and it is highly recommended that you take this time to read over that document as well to get a cursory understanding of Ember FW GC. Other details, such as serverside integration with Group Control can be found in the Auth Core documentation, but this is not necessary for you to read here at the beginning. It is linked here just for your convenience to refer back to if needed once you get to the final unit.