Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate /tutorial/part-2/ember-data.md, Ember 5.11 #268

Open
BlueCutOfficial opened this issue Oct 4, 2024 · 0 comments
Open

Translate /tutorial/part-2/ember-data.md, Ember 5.11 #268

BlueCutOfficial opened this issue Oct 4, 2024 · 0 comments
Labels
Guides FR trad File from the Ember Guides to translate in French

Comments

@BlueCutOfficial
Copy link
Member

Please assign yourself to the issue or let a comment at the very moment you start the translation.

File: guides/tutorial/part-2/ember-data.md
From Ember: 5.4
To Ember: 5.11

In the snippet below, you can see what changes were done in the latest English documentation. The purpose of this issue is to adjust the French translation to match the new version:

diff --git a/guides/tutorial/part-2/ember-data.md b/guides/tutorial/part-2/ember-data.md
index 72b3d9396..ba1926125 100644
--- a/guides/tutorial/part-2/ember-data.md
+++ b/guides/tutorial/part-2/ember-data.md
@@ -1,18 +1,18 @@
 <!-- Heads up! This is a generated file, do not edit directly. You can find the source at https://github.com/ember-learn/super-rentals-tutorial/blob/master/src/markdown/tutorial/part-2/11-ember-data.md -->
 
-In this chapter, we will work on removing some code duplication in our route handlers, by switching to using Ember Data to manage our data. The end result looks exactly the same as before:
+In this chapter, we will work on removing some code duplication in our route handlers, by switching to using EmberData to manage our data. The end result looks exactly the same as before:
 
-<img src="/images/tutorial/part-2/ember-data/[email protected]" alt="The Super Rentals app by the end of the chapter" width="1024" height="1129">
+<img src="/images/tutorial/part-2/ember-data/[email protected]" alt="The Super Rentals app by the end of the chapter" width="1024" height="1130">
 
 During this refactor, you will learn about:
 
-- Ember Data models
+- EmberData models
 - Testing models
 - Loading models in routes
-- The Ember Data store
-- Working with adapters and serializers
+- The EmberData Store and RequestManager
+- Working with Request builders and handlers
 
-## What is Ember Data?
+## What is EmberData?
 
 Now that we've added some features, it's time to do some clean up again!
 
@@ -72,13 +72,25 @@ This duplication incurred a bit of _technical debt_ for us, making our code base
 
 Chances are, as we keep working on this app, we will need to add more routes that fetch data from the server. Since all of our server's API endpoints follow the [JSON:API](https://jsonapi.org/) format, we'd have to keep copying this boilerplate for every single new route we add to the app!
 
-Fortunately, we're not going to do any of that. As it turns out, there's a much better solution here: we can use Ember Data! As its name implies, [Ember Data](../../../models/) is a library that helps manage data and _application state_ in Ember applications.
+Fortunately, we're not going to do any of that. As it turns out, there's a much better solution here: we can use EmberData! As its name implies, [EmberData](../../../models/) is a library that helps manage data and _application state_ in Ember applications.
 
-There's a lot to learn about Ember Data, but let's start by uncovering features that help with our immediate problem.
+There's a lot to learn about EmberData, but let's start by uncovering features that help with our immediate problem.
 
-## Ember Data Models
+<div class="cta">
+  <div class="cta-note">
+    <div class="cta-note-body">
+      <div class="cta-note-heading">Zoey says...</div>
+      <div class="cta-note-message">
+        <p>RequestManager is available starting with the EmberData 4.12 LTS release. EmberData works with multiple versions of Ember, please refer to the Compatibility section of the <a href="https://github.com/emberjs/data/blob/main/README.md#compatibility">EmberData README</a> while doing your application upgrade.</p>
+      </div>
+    </div>
+    <img src="/images/mascots/zoey.png" role="presentation" alt="">
+  </div>
+</div>
+
+## EmberData Models
 
-Ember Data is built around the idea of organizing your app's data into _[model objects](../../../models/defining-models/)_. These objects represent units of information that our application presents to the user. For example, the rental property data we have been working with would be a good candidate.
+EmberData is built around the idea of organizing your app's data into _[model objects](../../../models/defining-models/)_. These objects represent units of information that our application presents to the user. For example, the rental property data we have been working with would be a good candidate.
 
 Enough talking, why don't we give that a try!
 
@@ -107,14 +119,14 @@ export default class RentalModel extends Model {
 }
 
 
-Here, we created a `RentalModel` class that extends Ember Data's `Model` superclass. When fetching the listing data from the server, each individual rental property will be represented by an instance (also known as a _[record](../../../models/finding-records/)_ of our `RentalModel` class.
+Here, we created a `RentalModel` class that extends EmberData's `Model` superclass. When fetching the listing data from the server, each individual rental property will be represented by an instance (also known as a _[record](../../../models/finding-records/)_) of our `RentalModel` class.
 
 We used the `@attr` decorator to declare the attributes of a rental property. These attributes correspond directly to the `attributes` data we expect the server to provide in its responses:
 
 json { data-filename="public/api/rentals/grand-old-mansion.json" }
 {
   "data": {
-    "type": "rentals",
+    "type": "rental",
     "id": "grand-old-mansion",
     "attributes": {
       "title": "Grand Old Mansion",
@@ -135,7 +147,7 @@ We used the `@attr` decorator to declare the attributes of a rental property. Th
 
 We can access these attributes for an instance of `RentalModel` using standard dot notation, such as `model.title` or `model.location.lat`. In addition to the attributes we declared here, there will always be an implicit _id_ attribute as well, which is used to uniquely identify the model object and can be accessed using `model.id`.
 
-Model classes in Ember Data are no different than any other classes we've worked with so far, in that they allow for a convenient place for adding custom behavior. We took advantage of this feature to move our `type` logic (which is a major source of unnecessary duplication in our route handlers) into a getter on our model class. Once we have everything working here, we will go back to clean that up.
+Model classes in EmberData are no different than any other classes we've worked with so far, in that they allow for a convenient place for adding custom behavior. We took advantage of this feature to move our `type` logic (which is a major source of unnecessary duplication in our route handlers) into a getter on our model class. Once we have everything working here, we will go back to clean that up.
 
 Attributes declared with the `@attr` decorator work with the auto-track feature (which we learned about [in a previous chapter](../../part-1/reusable-components/)). Therefore, we are free to reference any model attributes in our getter (`this.category`), and Ember will know when to invalidate its result.
 
@@ -147,6 +159,8 @@ So far, we haven't had a good place to write tests for the rental property's `ty
 $ ember generate model-test rental
 installing model-test
   create tests/unit/models/rental-test.js
+
+Running "lint:fix" script...
 
 
 <div class="cta">
@@ -164,8 +178,8 @@ installing model-test
 The generator created some boilerplate code for us, which serves as a pretty good starting point for writing our test:
 
 js { data-filename="tests/unit/models/rental-test.js" data-diff="-7,-8,+9,-11,-12,+13,+14,+15,+16,+17,+18,+19,+20,+21,+22,+23,+24,+25,+26,+27,+28,+29,+30,+31,+32,+33,+34,+35,+36,+37,+38,+39,+40,+41,+42" }
-import { module, test } from 'qunit';
 import { setupTest } from 'super-rentals/tests/helpers';
+import { module, test } from 'qunit';
 
 module('Unit | Model | rental', function (hooks) {
   setupTest(hooks);
@@ -173,9 +187,9 @@ module('Unit | Model | rental', function (hooks) {
   // Replace this with your real tests.
   test('it exists', function (assert) {
   test('it has the right type', function (assert) {
-    let store = this.owner.lookup('service:store');
-    let model = store.createRecord('rental', {});
-    assert.ok(model);
+    const store = this.owner.lookup('service:store');
+    const model = store.createRecord('rental', {});
+    assert.ok(model, 'model exists');
     let rental = store.createRecord('rental', {
       id: 'grand-old-mansion',
       title: 'Grand Old Mansion',
@@ -212,7 +226,11 @@ module('Unit | Model | rental', function (hooks) {
 
 This model test is also known as a _[unit test](../../../testing/testing-models/)_. Unlike any of the other tests that we've written thus far, this test doesn't actually _render_ anything. It just instantiates the rental model object and tests the model object directly, manipulating its attributes and asserting their value.
 
-It is worth pointing out that Ember Data provides a `store` _[service](../../../services/)_, also known as the Ember Data store. In our test, we used the `this.owner.lookup('service:store')` API to get access to the Ember Data store. The store provides a `createRecord` method to instantiate our model object for us.
+It is worth pointing out that EmberData provides a `store` _[service](../../../services/)_, also known as the EmberData store. In our test, we used the `this.owner.lookup('service:store')` API to get access to the EmberData store. The store provides a `createRecord` method to instantiate our model object for us. To make this `store` service available, we must add the following file:
+
+js { data-filename="app/services/store.js" }
+export { default } from 'ember-data/store';
+
 
 Running the tests in the browser confirms that everything is working as intended:
 
@@ -220,13 +238,14 @@ Running the tests in the browser confirms that everything is working as intended
 
 ## Loading Models in Routes
 
-Alright, now that we have our model set up, it's time to refactor our route handlers to use Ember Data and remove the duplication!
+Alright, now that we have our model set up, it's time to refactor our route handlers to use EmberData and remove the duplication!
 
-js { data-filename="app/routes/index.js" data-diff="-2,-3,+4,-7,-8,-9,-10,-11,-12,-13,+14,-16,-17,-18,-19,-20,-21,-22,-23,+24,+25" }
+js { data-filename="app/routes/index.js" data-diff="-2,-3,+4,+5,-8,-9,-10,-11,-12,-13,-14,+15,-17,-18,-19,-20,-21,-22,-23,-24,+25,+26,+27" }
 import Route from '@ember/routing/route';
 
 const COMMUNITY_CATEGORIES = ['Condo', 'Townhouse', 'Apartment'];
 import { service } from '@ember/service';
+import { query } from '@ember-data/json-api/request';
 
 export default class IndexRoute extends Route {
   async model() {
@@ -247,16 +266,18 @@ export default class IndexRoute extends Route {
       return { id, type, ...attributes };
     });
   async model() {
-    return this.store.findAll('rental');
+    const { content } = await this.store.request(query('rental'));
+    return content.data;
   }
 }
 
 
-js { data-filename="app/routes/rental.js" data-diff="-2,-3,+4,-7,-8,-9,-10,-11,-12,+13,-15,-16,-17,-18,-19,-20,-21,+22,+23" }
+js { data-filename="app/routes/rental.js" data-diff="-2,-3,+4,+5,-8,-9,-10,-11,-12,-13,+14,-16,-17,-18,-19,-20,-21,-22,+23,+24,+25,+26,+27" }
 import Route from '@ember/routing/route';
 
 const COMMUNITY_CATEGORIES = ['Condo', 'Townhouse', 'Apartment'];
 import { service } from '@ember/service';
+import { findRecord } from '@ember-data/json-api/request';
 
 export default class RentalRoute extends Route {
   async model(params) {
@@ -275,18 +296,21 @@ export default class RentalRoute extends Route {
 
     return { id, type, ...attributes };
   async model(params) {
-    return this.store.findRecord('rental', params.rental_id);
+    const { content } = await this.store.request(
+      findRecord('rental', params.rental_id),
+    );
+    return content.data;
   }
 }
 
 
 Wow... that removed a lot of code! This is all possible thanks to the power of conventions!
 
-## The Ember Data Store
+## The EmberData Store
 
-As mentioned above, Ember Data provides a `store` service, which we can inject into our route using the `@service store;` declaration, making the Ember Data store available as `this.store`. It provides the `find` and `findAll` methods for loading records. Specifically, the [`findRecord` method](../../../models/finding-records/#toc_retrieving-a-single-record) takes a model type (`rental` in our case) and a model ID (for us, that would be `params.rental_id` from the URL) as arguments and fetches a single record from the store. On the other hand, the [`findAll` method](../../../models/finding-records/#toc_retrieving-multiple-records) takes the model type as an argument and fetches all records of that type from the store.
+As mentioned above, EmberData provides a `store` service, which we can inject into our route using the `@service store;` declaration, making the EmberData store available as `this.store`. It provides the `request` method for making fetch requests using `RequestManager`. As its name implies: the `RequestManager` is request centric. Instead of answering questions about specific records or types of records, we ask it about the status of a specific request. To initiate a request, we use the `request` method on the store, passing in a request object. The request object is created using builders from `@ember-data/json-api/request`. Specifically, the [`findRecord` builder](../../../models/finding-records/#toc_retrieving-a-single-record) takes a model type (`rental` in our case) and a model ID (for us, that would be `params.rental_id` from the URL) as arguments and builds fetch options for a single record. On the other hand, the [`query` builder](../../../models/finding-records/#toc_retrieving-multiple-records) takes the model type as an argument and builds fetch options to query for all records of that type.
 
-The Ember Data store acts as a kind of intermediary between our app and the server; it does many important things, including caching the responses that were fetched from the server. If we request some records (instances of model classes) that we had _already_ fetched from the server in the past, Ember Data's store ensures that we can access the records immediately, without having to fetch them again unnecessarily and wait for the server to respond. But, if we don't already have that response cached in our store, then it will go off and fetches it from the server. Pretty nice, right?
+EmberData can do many things, and in default setup it provides caching. EmberData's store caches server responses, allowing instant access to previously fetched data. If the data is already cached, you don't need to wait for the server to respond again. If not, the store fetches it for you.
 
 That's a lot of theory, but is this going to work in our app? Let's run the tests and find out!
 
@@ -296,60 +320,96 @@ Darn, there were a couple of failing tests! At the same time, it's great that we
 
 Looking at the failure messages, the problem appears to be that the store went to the wrong URLs when fetching data from the server, resulting in some 404 errors. Specifically:
 
-- When performing the `findAll('rental')` query, it requested the data from `/rentals`, instead of `/api/rentals.json`.
-- When performing the `find('rental', 'grand-old-mansion')` query, it requested the data from `/rentals/grand-old-mansion`, instead of `/api/rentals/grand-old-mansion.json`.
+- When building the `query('rental')` request, the resulted `url` in request options was `/rentals`, instead of `/api/rentals.json`.
+- When building the `findRecord('rental', 'grand-old-mansion')` request, the resulted `url` in request options was `/rentals/grand-old-mansion`, instead of `/api/rentals/grand-old-mansion.json`.
 
-Hm, okay, so we have to teach Ember Data to fetch data from the correct location. But how does Ember Data know how to fetch data from our server in the first place?
+Hm, okay, so we have to teach EmberData to fetch data from the correct location. But how does EmberData know how to fetch data from our server in the first place?
 
-## Working with Adapters and Serializers
+## Working with Request builders and Handlers
 
-Ember Data uses an _[adapter](../../../models/customizing-adapters/)_ and _[serializer](../../../models/customizing-serializers/)_ architecture. Adapters deal with _how_ and _where_ Ember Data should fetch data from your servers, such as whether to use HTTP, HTTPS, WebSockets or local storage, as well as the URLs, headers and parameters to use for these requests. On the other hand, serializers are in charge of converting the data returned by the server into a format Ember Data can understand.
+Let's start customizing the things that didn't work for us by default. Specifically:
 
-The idea is that, provided that your backend exposes a _consistent_ protocol and interchange format to access its data, we can write a single adapter-serializer pair to handle all data fetches for the entire application.
-
-As it turns out, JSON:API just happens to be Ember Data's default data protocol and interchange format. Out of the box, Ember Data provides a default JSON:API adapter and serializer. This is great news for us, since that is also what our server has implemented. What a wonderful coincidence!
+- Our resource URLs have an extra `/api` _namespace_ prefix.
+- Our resource URLs have a `.json` extension at the end.
 
-However, as mentioned above, there are some minor differences between how our server works and Ember Data's default assumptions. We can customize the default behavior by defining our own adapter and serializer:
+The first thing we want to do is have our builder respect a configurable default host and/or namespace. Adding a namespace prefix happens to be pretty common across Ember apps, so EmberData provides a global config mechanism for host and namespace. Typically you will want to do this either in your store file or app file.
 
-js { data-filename="app/adapters/application.js" }
-import JSONAPIAdapter from '@ember-data/adapter/json-api';
+js { data-filename="app/app.js" data-diff="+5,+6,+7,+8,+9" }
+import Application from '@ember/application';
+import Resolver from 'ember-resolver';
+import loadInitializers from 'ember-load-initializers';
+import config from 'super-rentals/config/environment';
+import { setBuildURLConfig } from '@ember-data/request-utils';
 
-export default class ApplicationAdapter extends JSONAPIAdapter {
-  namespace = 'api';
+setBuildURLConfig({
+  namespace: 'api',
+});
 
-  buildURL(...args) {
-    return `${super.buildURL(...args)}.json`;
-  }
+export default class App extends Application {
+  modulePrefix = config.modulePrefix;
+  podModulePrefix = config.podModulePrefix;
+  Resolver = Resolver;
 }
+
+loadInitializers(App, config.modulePrefix);
 
 
-js { data-filename="app/serializers/application.js" }
-import JSONAPISerializer from '@ember-data/serializer/json-api';
+Adding the `.json` extension is a bit less common, and doesn't have a declarative configuration API of its own. We could just modify request options directly in place of use, but that would be a bit messy. Instead, let's create a handler to do this for us.
 
-export default class ApplicationSerializer extends JSONAPISerializer {}
+js { data-filename="app/utils/handlers.js" }
+export const JsonSuffixHandler = {
+  request(context, next) {
+    const { request } = context;
+    const updatedRequest = Object.assign({}, request, {
+      url: request.url + '.json',
+    });
+
+    return next(updatedRequest);
+  },
+};
 
 
-By convention, adapters are located at `app/adapters`. Furthermore, the adapter named `application` is called the _application adapter_, which will be used to fetch data for all models in our app.
+As you can see, the handler appends `.json` to the URL of each request. Pretty simple, right? Then it calls the `next` function with the modified copy of the request object (because it is immutable). This is how we can chain multiple handlers together to build up a request.
 
-Inside this newly created file, we defined an `ApplicationAdapter` class, inheriting from the built-in [`JSONAPIAdapter`](https://api.emberjs.com/ember-data/release/classes/JSONAPIAdapter). This allows us to inherit all the default JSON:API functionalities, while customizing the things that didn't work for us by default. Specifically:
+The next step that we need to do, is to configure `RequestManager` to use this handler. Let's create the request-manager service.
 
-- Our resource URLs have an extra `/api` _namespace_ prefix.
-- Our resource URLs have a `.json` extension at the end.
+js { data-filename="app/services/request-manager.js" }
+import BaseRequestManager from '@ember-data/request';
+import Fetch from '@ember-data/request/fetch';
+import { JsonSuffixHandler } from 'super-rentals/utils/handlers';
 
-Adding a namespace prefix happens to be pretty common across Ember apps, so the `JSONAPIAdapter` has an API to do just that. All we need to do is to set the  `namespace` property to the prefix we want, which is `api` in our case.
+export default class RequestManager extends BaseRequestManager {
+  constructor(args) {
+    super(args);
 
-Adding the `.json` extension is a bit less common, and doesn't have a declarative configuration API of its own. Instead, we will need to _override_ Ember Data's [`buildURL`](https://api.emberjs.com/ember-data/release/classes/JSONAPIAdapter/methods/buildURL?anchor=buildURL) method. Inside of `buildURL`, we will call `super.buildURL(...args)` to invoke the `JSONAPIAdapter` default implementation of `buildURL`. This will give us the URL that the adapter _would have built_, which would be something like `/api/rentals` and `/api/rentals/grand-old-mansion` after configuring the `namespace` above. All we have to do is to append `.json` to this URL and return it.
+    this.use([JsonSuffixHandler, Fetch]);
+  }
+}
+
+
+Notice that we are using the `JsonSuffixHandler` we created earlier. We also use the `Fetch` handler, which is a built-in handler that makes the actual fetch request. The `use` method is used to add handlers to the request manager. The order in which handlers are added is important, as they will be executed in the order they were added.
+
+Lastly, let's update our `store` service to use the new `RequestManager` we created.
 
-Similarly, serializers are located at `app/serializers`. Adapters and serializers are always added together as a pair. We added an `application` adapter, so we also added a corresponding serializer to go with it as well. Since the JSON data returned by our server is JSON:API-compliant, the default [`JSONAPISerializer`](https://api.emberjs.com/ember-data/release/classes/JSONAPISerializer) work just fine for us without further customization.
+js { data-filename="app/services/store.js" data-diff="-1,+2,+3,+4,+5,+6,+7,+8" }
+export { default } from 'ember-data/store';
+// eslint-disable-next-line ember/use-ember-data-rfc-395-imports
+import BaseStore from 'ember-data/store';
+import { service } from '@ember/service';
+
+export default class Store extends BaseStore {
+  @service requestManager;
+}
+
 
-With our adapter and serializer in place, all our tests should pass again.
+With our new EmberData configuration in place, all our tests should pass again.
 
 <img src="/images/tutorial/part-2/ember-data/[email protected]" alt="Once again, all the tests are passing again!" width="1024" height="1024">
 
 The UI works exactly the same as before as well, just with much less code!
 
-<img src="/images/tutorial/part-2/ember-data/[email protected]" alt="The homepage works exactly the same as before, but with much less code!" width="1024" height="1129">
+<img src="/images/tutorial/part-2/ember-data/[email protected]" alt="The homepage works exactly the same as before, but with much less code!" width="1024" height="1130">
 
-<img src="/images/tutorial/part-2/ember-data/[email protected]" alt="The details page works exactly the same as before, but with much less code!" width="1024" height="1381">
+<img src="/images/tutorial/part-2/ember-data/[email protected]" alt="The details page works exactly the same as before, but with much less code!" width="1024" height="1382">
 
-Ember Data offers many, many features (like managing the _relationships_ between different models) and there's a lot more we can learn about it. For example, if your backend's have some inconsistencies across different endpoints, Ember Data allows you to define more specific, per-model adapters and serializers too! We are just scratching the surface here. If you want to learn more about Ember Data, check out [its own dedicated section](../../../models/) in the guides!
+EmberData offers many, many features (like managing the _relationships_ between different models) and there's a lot more we can learn about it. For example, if your backend's have some inconsistencies across different endpoints, EmberData allows you to define request specific handlers and builders! We are just scratching the surface here. If you want to learn more about EmberData, check out [its own dedicated section](../../../models/) in the guides!
@BlueCutOfficial BlueCutOfficial added the Guides FR trad File from the Ember Guides to translate in French label Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Guides FR trad File from the Ember Guides to translate in French
Projects
None yet
Development

No branches or pull requests

1 participant