# Ember DATA

{% embed url="<https://guides.emberjs.com/release/models/>" %}

## Store

The store is a service provided by Ember. It will allow you to **keep all the data loaded from the backend** while the session is active. Newly created record will also be present in the store, even before they're sent to the backend in order to be persisted.

You will mostly need it in your routes, controllers and components. To use it, you need to import the service `import { inject as service } from '@ember/service';` , then declare it in your class as an attribute:

```javascript
// Ember Classic
store: service(),

//Ember Octane
@service store;
```

We will now see how the store keeps its data, and how to interact with it.

## Models

In Ember Data, models are objects that represent the underlying data that your application presents to the user.&#x20;

Models tend to be persistent. That means the user does not expect model data to be lost when they close their browser window. To make sure no data is lost, if the user makes changes to a model, you need to store the model data somewhere that it will not be lost.

Typically, most models are loaded from and saved to a server that uses a database to store data. Usually you will send JSON representations of models back and forth to an HTTP server that you have written. In our case, data will be send via the help of our dear [adapters](https://prospect-io.gitbook.io/developer-playbook/our-stack/ember.js/ember_to_rails).

We will now come back a bit about the basics, but don't leave quite yet if you're comfortable with that. The last section of this page talks about how we **serialize** **nested attributes** rightly for the back-end and that might interest you.

### Model vs model()

Ember Data models share the same name with the *model method* on routes, although they are a different concept.

**The** `model()` **method of a given route will set the model attribute of its corresponding controller**, through the `setupController()` method

For example, let's analyse this model method:

```javascript
model(params) {
    return this.store.findRecord('company', params.company_id);
}
```

In this case, this method returns an instance of a Company, which is the Model class representing our company object, and **it will be assigned to the model attribute of the corresponding controller**.

```javascript
controller.model // Contains the company returned by the model() method
```

### Model Class

Model classes represents all data records, mostly provided by both the backend and the user. With Ember, we implement our model classes by extending the Ember `DS.Model` class.

Inside the class, we simply have to declare the record's attributes and relationships. We can implement methods and computed attributes and we also have the possibility of having validations on our model (as a constant).

Check this out with this next example, it is the model of an user (`user.js`):

```javascript
import DS from 'ember-data';
import {belongsTo, hasMany} from 'ember-data/relationships';
import {buildValidations, validator} from 'ember-cp-validations';

const {attr, belongsTo, hasMany} = DS;

const Validations = buildValidations({
  firstName: [
    validator('presence', {
      presence: true,
      message: 'this field can\'t be blank'
    })
  ]
});

export default DS.Model.extend(Validations, {
  company: belongsTo('company', { async: false }),
  lines: hasMany:('line', { async:false }),
  
  firstName: attr('string'),
  email: attr('string')
  
  firstNameOrEmail: computed('firstName', 'email', function(){
    return this.get('firstName') || this.get('email');
  })
});
```

## Finding Records

If we want to retrieve a single record, we can use the store by either calling `findRecord()` or `peekRecord()`.

```javascript
let company = this.store.findRecord('company', 1); // GET api/private/companies/1
let company = this.store.peekRecord('company', 1); // No network request
```

The difference between those two methods are that the first one is going to **send a GET request** to the backend, while the second one will just **search in the store**, and return the data it if it is already there.

The calls above will resolve in an instance of `Company`, which inherits from `ember-data/model` like all Ember Data models do.

If you want to retrieve all records of a specific model, the procedure is quite similar. The only difference is that you are going to call `findAll('company')` or `peekAll('company')` on the store.

## Creating Records

**To create a new record**, we will once again use the store by calling its `createRecord()` method.

```javascript
let company = store.createRecord('company', {
  name: 'Prospect.io'
});
```

## Persisting Records

The company we created below **exists in the Ember store**, **but has not been persisted in our backend**.&#x20;

**To persist a record**, we will call the `save()` method directly on the record, which will send a POST request to our backend, and the later will be in charge of saving the record in our database. In other words, Ember will say to Rails: "*Hey, I've just created this new company, could you please  save it for me?"*.

```javascript
company.save();
```

### Nested attributes

The company we have just created has a pretty cool name, but it lacks some employees. Indeed, a company should have multiple employees working for it (this is a *one-to-many* relationship).&#x20;

Now, we want to assign all the employees to this company. Let's imagine we have a variable `allEmployees` that consists of an array containing every employee of this company (considering an employee being an instance of the model class `employee.js`). How do we assign it to the company?

First, our `company` model must have the right attribute. In this case, it would be `employees: hasMany('employee', { async: false })`. In parallel, our `employee` model also has to define the symmetrical attribute, which would be: `company: belongsTo('company', { async: false })`. Note here that both end of our one-to-many relation are explicit in both attributes (**hasMany & belongsTo**).

If we have that, we can simply do:

```javascript
company.employees = allEmployees;
```

Great! Our company now has a cool name and awesome people working for it. But don't forget, we have to save it in order to persist the data. Otherwise, all the people will be gone the next time you come back.

Here is the touchy part: calling the `save()` method on the company won't send every employees to the backend, **it will just send their IDs**. As some of them could be newly created, they won't have an ID yet.\
In this case, we want to send plain objects (the company instance + every instance of its employees).

But don't worry, we have the solution! At Prospect.io, we developed a **custom mixin** that you can use to **serialize records with nested entities**.                                                                                                           Basically, we need to create a **custom serializer** for our parent record (in this case, the company), and this serializer has to implement our `IncludedRecordsMixin`. \
\
In our example, we will call this serializer `company.js` and place the file in the `serializers` folder of our frontend application.

```javascript
import Application from './application';
import IncludedRecordsMixin from './mixins/included-records';

export default Application.extend(IncludedRecordsMixin, {
  attrs: {
    employees: {
      serialize: 'included'
    }
  }
});

```

And voilà! With that serializer, calling `company.save()` will now send the company & every instances of its employees to the backend.&#x20;

As we saw, before doing that **we just had the IDs** of every employees, and you could find them in the `relationships` attribute of the JSON sent to the backend.

Now, in addition to that, we will have **every serialized employee** in the `included` attribute of the same JSON. If you want more informations, don't hesitate to check out this awesome [guide](https://guides.emberjs.com/v2.14.0/models/customizing-serializers).

You can now go to the [next section](https://prospect-io.gitbook.io/developer-playbook/our-stack/ember.js/ember_to_rails) to see how Ember helps us sending this serialized data to the backend!
