Skip to content

Commit 45036d3

Browse files
authored
Merge pull request #2187 from ember-learn/super-rentals-tutorial
Tutorial Updates
2 parents e98d992 + 44b8a46 commit 45036d3

File tree

4 files changed

+88
-57
lines changed

4 files changed

+88
-57
lines changed

guides/release/tutorial/part-1/orientation.md

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ To verify that your installation was successful, run:
2424

2525
```shell
2626
$ ember --version
27-
ember-cli: 6.9.1
28-
node: 20.19.6
27+
ember-cli: 6.10.0
28+
node: 20.20.0
2929
os: linux x64
3030
```
3131

@@ -46,29 +46,28 @@ Creating a new Ember app in /home/runner/work/super-rentals-tutorial/super-renta
4646
create .prettierignore
4747
create .prettierrc.mjs
4848
create .stylelintignore
49-
create .stylelintrc.cjs
49+
create .stylelintrc.mjs
5050
create .template-lintrc.mjs
5151
create .watchmanconfig
5252
create README.md
53-
create /home/runner/work/super-rentals-tutorial/super-rentals-tutorial/dist/code/super-rentals/babel.config.cjs
54-
create /home/runner/work/super-rentals-tutorial/super-rentals-tutorial/dist/code/super-rentals/eslint.config.mjs
5553
create app/app.js
5654
create app/components/.gitkeep
5755
create app/config/environment.js
5856
create app/controllers/.gitkeep
5957
create app/deprecation-workflow.js
6058
create app/helpers/.gitkeep
61-
create app/models/.gitkeep
6259
create app/router.js
6360
create app/routes/.gitkeep
64-
create app/services/.gitkeep
61+
create app/services/store.js
6562
create app/styles/app.css
66-
create /home/runner/work/super-rentals-tutorial/super-rentals-tutorial/dist/code/super-rentals/app/templates/application.gjs
63+
create app/templates/application.gjs
64+
create babel.config.mjs
6765
create config/ember-cli-update.json
6866
create config/environment.js
6967
create config/optional-features.json
7068
create config/targets.js
7169
create ember-cli-build.js
70+
create eslint.config.mjs
7271
create .gitignore
7372
create index.html
7473
create package.json
@@ -119,12 +118,10 @@ super-rentals
119118
│ │ └── .gitkeep
120119
│ ├── helpers
121120
│ │ └── .gitkeep
122-
│ ├── models
123-
│ │ └── .gitkeep
124121
│ ├── routes
125122
│ │ └── .gitkeep
126123
│ ├── services
127-
│ │ └── .gitkeep
124+
│ │ └── store.js
128125
│ ├── styles
129126
│ │ └── app.css
130127
│ ├── templates
@@ -137,6 +134,28 @@ super-rentals
137134
│ ├── environment.js
138135
│ ├── optional-features.json
139136
│ └── targets.js
137+
├── dist
138+
│ ├── @embroider
139+
│ │ └── virtual
140+
│ │ ├── app.css
141+
│ │ ├── test-support.css
142+
│ │ ├── test-support.js
143+
│ │ ├── vendor.css
144+
│ │ └── vendor.js
145+
│ ├── assets
146+
│ │ ├── app-BQizcYp5.js
147+
│ │ ├── app-BsLReVUA.css
148+
│ │ ├── main-BrJmI0E2.js
149+
│ │ ├── modules-4-12-1Tpr-lU6.js
150+
│ │ ├── tests-Bfhe-jay.js
151+
│ │ └── tests-CFFHI-JI.css
152+
│ ├── ember-welcome-page
153+
│ │ └── construction.png
154+
│ ├── tests
155+
│ │ └── index.html
156+
│ ├── index.html
157+
│ ├── robots.txt
158+
│ └── testem.js
140159
├── public
141160
│ └── robots.txt
142161
├── tests
@@ -148,18 +167,21 @@ super-rentals
148167
│ │ └── .gitkeep
149168
│ ├── index.html
150169
│ └── test-helper.js
170+
├── tmp
171+
│ └── compat-prebuild
172+
│ └── .stage2-output
151173
├── .editorconfig
152174
├── .ember-cli
153175
├── .env.development
154176
├── .gitignore
155177
├── .prettierignore
156178
├── .prettierrc.mjs
157179
├── .stylelintignore
158-
├── .stylelintrc.cjs
180+
├── .stylelintrc.mjs
159181
├── .template-lintrc.mjs
160182
├── .watchmanconfig
161183
├── README.md
162-
├── babel.config.cjs
184+
├── babel.config.mjs
163185
├── ember-cli-build.js
164186
├── eslint.config.mjs
165187
├── index.html
@@ -168,7 +190,7 @@ super-rentals
168190
├── testem.cjs
169191
└── vite.config.mjs
170192
171-
28 directories, 58 files
193+
26 directories, 57 files
172194
```
173195

174196
We'll learn about the purposes of these files and folders as we go. For now, just know that we'll spend most of our time working within the `app` folder.
@@ -195,18 +217,18 @@ Build successful (9761ms)
195217

196218
Slowest Nodes (totalTime >= 5%) | Total (avg)
197219
-+-
198-
Babel: @embroider/macros (1) | 389ms
220+
Babel: @embroider/macros (1) | 417ms
199221

200222

201223

202-
VITE v7.3.0 ready in 3754 ms
224+
VITE v7.3.1 ready in 3542 ms
203225

204226
➜ Local: http://localhost:4200/
205227
```
206228

207229
The development server is responsible for compiling our app and serving it to the browsers. It may take a while to boot up. Once it's up and running, open your favorite browser and head to <http://localhost:4200>. You should see the following welcome page:
208230

209-
<img src="/images/tutorial/part-1/orientation/welcome@2x.png" alt="Welcome to Ember!" width="1024" height="919">
231+
<img src="/images/tutorial/part-1/orientation/welcome@2x.png" alt="Welcome to Ember!" width="1024" height="964">
210232

211233
<div class="cta">
212234
<div class="cta-note">
@@ -238,7 +260,7 @@ import { WelcomePage } from 'ember-welcome-page';
238260
{{outlet}}
239261
240262
{{! The following component displays Ember's default welcome message. }}
241-
<WelcomePage />
263+
<WelcomePage @extension="gjs" />
242264
{{! Feel free to remove this! }}
243265
Hello World!!!
244266
</template>

guides/release/tutorial/part-1/reusable-components.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ Build successful (13286ms)
102102

103103
Slowest Nodes (totalTime >= 5%) | Total (avg)
104104
-+-
105-
Babel: @embroider/macros (1) | 389ms
105+
Babel: @embroider/macros (1) | 432ms
106106

107107

108108

109-
VITE v7.3.0 ready in 3756 ms
109+
VITE v7.3.1 ready in 3695 ms
110110

111111
➜ Local: http://localhost:4200/
112112
```

guides/release/tutorial/part-2/ember-data.md

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -74,28 +74,28 @@ Chances are, as we keep working on this app, we will need to add more routes tha
7474

7575
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.
7676

77-
There's a lot to learn about EmberData, but let's start by uncovering features that help with our immediate problem.
78-
7977
<div class="cta">
8078
<div class="cta-note">
8179
<div class="cta-note-body">
8280
<div class="cta-note-heading">Zoey says...</div>
8381
<div class="cta-note-message">
84-
<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>
82+
<p>EmberData is in the process of being renamed to WarpDrive. It's not just changing its name though, WarpDrive is now able to be used in multiple different frameworks. You can read more about it in the <a href="https://warp-drive.io">WarpDrive Docs</a></p>
8583
</div>
8684
</div>
8785
<img src="/images/mascots/zoey.png" role="presentation" alt="">
8886
</div>
8987
</div>
9088

89+
There's a lot to learn about EmberData, but let's start by uncovering features that help with our immediate problem.
90+
9191
## EmberData Models
9292

9393
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.
9494

9595
Enough talking, why don't we give that a try!
9696

9797
```js { data-filename="app/models/rental.js" }
98-
import Model, { attr } from '@ember-data/model';
98+
import Model, { attr } from '@warp-drive/legacy/model';
9999

100100
const COMMUNITY_CATEGORIES = ['Condo', 'Townhouse', 'Apartment'];
101101

@@ -119,7 +119,7 @@ export default class RentalModel extends Model {
119119
}
120120
```
121121

122-
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.
122+
Here, we created a `RentalModel` class that extends EmberData's `Model` superclass (which is imported from the `@warp-drive/legacy` package). 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.
123123

124124
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:
125125

@@ -226,10 +226,26 @@ module('Unit | Model | rental', function (hooks) {
226226
227227
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.
228228
229-
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:
229+
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.
230+
231+
This is the store that is generated for us as part of the default blueprint:
230232
231233
```js { data-filename="app/services/store.js" }
232-
export { default } from 'ember-data/store';
234+
import { useLegacyStore } from '@warp-drive/legacy';
235+
import { JSONAPICache } from '@warp-drive/json-api';
236+
237+
const Store = useLegacyStore({
238+
linksMode: false,
239+
cache: JSONAPICache,
240+
handlers: [
241+
// -- your handlers here
242+
],
243+
schemas: [
244+
// -- your schemas here
245+
],
246+
});
247+
248+
export default Store;
233249
```
234250
235251
Running the tests in the browser confirms that everything is working as intended:
@@ -245,7 +261,7 @@ import Route from '@ember/routing/route';
245261

246262
const COMMUNITY_CATEGORIES = ['Condo', 'Townhouse', 'Apartment'];
247263
import { service } from '@ember/service';
248-
import { query } from '@ember-data/json-api/request';
264+
import { query } from '@warp-drive/utilities/json-api';
249265

250266
export default class IndexRoute extends Route {
251267
async model() {
@@ -277,7 +293,7 @@ import Route from '@ember/routing/route';
277293

278294
const COMMUNITY_CATEGORIES = ['Condo', 'Townhouse', 'Apartment'];
279295
import { service } from '@ember/service';
280-
import { findRecord } from '@ember-data/json-api/request';
296+
import { findRecord } from '@warp-drive/utilities/json-api';
281297

282298
export default class RentalRoute extends Route {
283299
async model(params) {
@@ -308,9 +324,9 @@ Wow... that removed a lot of code! This is all possible thanks to the power of c
308324
309325
## The EmberData Store
310326
311-
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.
327+
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 `@warp-drive/utilities/json-api`. 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.
312328
313-
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.
329+
EmberData can do many things, and in the 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.
314330
315331
That's a lot of theory, but is this going to work in our app? Let's run the tests and find out!
316332
@@ -334,7 +350,8 @@ Let's start customizing the things that didn't work for us by default. Specifica
334350
335351
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.
336352
337-
```js { data-filename="app/app.js" data-diff="+21,+22,+23,+24,+25" }
353+
```js { data-filename="app/app.js" data-diff="+22,+23,+24,+25,+26" }
354+
import '@warp-drive/ember/install';
338355
import Application from '@ember/application';
339356
import compatModules from '@embroider/virtual/compat-modules';
340357
import Resolver from 'ember-resolver';
@@ -355,7 +372,7 @@ export default class App extends Application {
355372
}
356373

357374
loadInitializers(App, config.modulePrefix, compatModules);
358-
import { setBuildURLConfig } from '@ember-data/request-utils';
375+
import { setBuildURLConfig } from '@warp-drive/utilities/json-api';
359376

360377
setBuildURLConfig({
361378
namespace: 'api',
@@ -379,34 +396,26 @@ export const JsonSuffixHandler = {
379396
380397
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.
381398
382-
The next step that we need to do, is to configure `RequestManager` to use this handler. Let's create the request-manager service.
399+
The next step that we need to do, is to configure our `legacyStore` to use this handler. Let's update the store service to add this handler:
383400
384-
```js { data-filename="app/services/request-manager.js" }
385-
import BaseRequestManager from '@ember-data/request';
386-
import Fetch from '@ember-data/request/fetch';
401+
```js { data-filename="app/services/store.js" data-diff="+3,+10" }
402+
import { useLegacyStore } from '@warp-drive/legacy';
403+
import { JSONAPICache } from '@warp-drive/json-api';
387404
import { JsonSuffixHandler } from 'super-rentals/utils/handlers';
388405

389-
export default class RequestManager extends BaseRequestManager {
390-
constructor(args) {
391-
super(args);
392-
393-
this.use([JsonSuffixHandler, Fetch]);
394-
}
395-
}
396-
```
397-
398-
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.
399-
400-
Lastly, let's update our `store` service to use the new `RequestManager` we created.
401-
402-
```js { data-filename="app/services/store.js" data-diff="-1,+2,+3,+4,+5,+6,+7" }
403-
export { default } from 'ember-data/store';
404-
import BaseStore from 'ember-data/store';
405-
import { service } from '@ember/service';
406+
const Store = useLegacyStore({
407+
linksMode: false,
408+
cache: JSONAPICache,
409+
handlers: [
410+
// -- your handlers here
411+
JsonSuffixHandler
412+
],
413+
schemas: [
414+
// -- your schemas here
415+
],
416+
});
406417

407-
export default class Store extends BaseStore {
408-
@service requestManager;
409-
}
418+
export default Store;
410419
```
411420
412421
With our new EmberData configuration in place, all our tests should pass again.
-99.7 KB
Loading

0 commit comments

Comments
 (0)