<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ ember - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ ember - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 30 May 2026 22:26:24 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/ember/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Ember QuickTips: How to breakup and import SASS/CSS files separately ]]>
                </title>
                <description>
                    <![CDATA[ By Michael Xavier There are times when it’s desirable to break up your stylesheets into multiple files and import them into your project separately. This came up in a side project I started recently, and I thought y’all might benefit from what I came... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/ember-quicktips-how-to-breakup-and-import-sass-css-files-separately-b0759459027d/</link>
                <guid isPermaLink="false">66d46042f855545810e934a5</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ember ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sass ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 11 Jan 2019 17:50:43 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*ZVmLA6aPZFWbG6UDK5nEfw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Michael Xavier</p>
<p>There are times when it’s desirable to <strong>break up your stylesheets into multiple files and import them into your project separately</strong>. This came up in a side project I started recently, and I thought y’all might benefit from what I came up with as a solution. It’s a quick and easy method, so let’s get started ?</p>
<p>When you begin a new EmberJS app you’ll notice that the <code>index.html</code> file imports the main stylesheet into the app like so:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
 ...
 <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">integrity</span>=<span class="hljs-string">""</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"{{rootURL}}assets/test-app.css"</span>
 &gt;</span>
 ...
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p><code>test-app.css</code> is compiled directly from your project. When we write our custom styles in <code>app/styles/app.css</code> they get put into this file.</p>
<p>Now, what if we don’t want to import all of our styles into the app as a single stylesheet? <strong>How can we breakup our styles and import multiple stylesheets into the app?</strong> Something like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
 ...
 <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">integrity</span>=<span class="hljs-string">""</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"{{rootURL}}assets/test-app.css"</span>
 &gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">integrity</span>=<span class="hljs-string">""</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"{{rootURL}}assets/second-stylesheet.css"</span>
 &gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>It may be easier than you think ?</p>
<h3 id="heading-step-one-write-styles-in-scsssass-and-compile-to-css">Step One: Write styles in SCSS/SASS and compile to CSS</h3>
<p>First, install a SASS preprocessor to compile SCSS/SASS stylesheets into CSS stylesheets. For this example I’ll use <code>ember-cli-sass</code>:</p>
<pre><code>ember install ember-cli-sass
</code></pre><p>Now rename <code>app/styles/app.css</code> to <code>app/styles/app.scss</code>. The preprocessor will take care of processing and compiling your stylesheet automatically.</p>
<p>If you run the app the Ember welcome page should display as usual:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/aYuzVPXdJ4BtKQenSZFHhS-C-GDrL2LS7Ryf" alt="Image" width="800" height="579" loading="lazy">
<em>Nothing has changed. That’s good.</em></p>
<p>Comment out <code>{{welcome-page}}</code> in <code>app/templates/application.hbs</code> before you continue. We now have a blank DOM to work with.</p>
<h3 id="heading-step-two-create-a-new-stylesheet">Step Two: Create a new stylesheet</h3>
<p>Let’s create a new stylesheet called <code>app/styles/second-stylesheet.scss</code> and add the following styles:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
 <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
 <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
 <span class="hljs-attribute">background-color</span>: red;
}
</code></pre>
<p>A glaring red background would be very obvious, yet when you run the server you see nothing but a sea of white. Why is this?</p>
<p>If your instinct was to import it into the project as specified above, you would be correct:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
 ...
 <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">integrity</span>=<span class="hljs-string">""</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"{{rootURL}}assets/second-stylesheet.css"</span>
 &gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>Yet, it still doesn’t show up. Why? ? That’s because the build pipeline hasn’t been configured to build this file in the correct folder just yet.</p>
<h3 id="heading-step-three-configure-ember-cli-build">Step Three: Configure Ember-CLI-Build</h3>
<p>The final step is to tell the Ember app that you have a <code>css</code> file to include in its build pipeline.</p>
<p>In <code>ember-cli-build.js</code> add the following:</p>
<pre><code class="lang-js">...
module.exports = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">defaults</span>) </span>{
  <span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> EmberApp(defaults, {
    <span class="hljs-comment">// Add options here</span>
    <span class="hljs-attr">outputPaths</span>: {
      <span class="hljs-attr">app</span>: {
        <span class="hljs-attr">css</span>: {
          <span class="hljs-string">'second-stylesheet'</span>: <span class="hljs-string">'/assets/second-stylesheet.css'</span>
        }
      }
    }

  });
  ...
};
</code></pre>
<p><strong>That’s it!</strong> ? This tells Ember where to output your new stylesheet so that it can be properly accessed in your i<code>ndex.html</code> ?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/EY9F7DHJAzzfJqcwOS9Ft-TyL78cFd5nYfuE" alt="Image" width="800" height="517" loading="lazy">
<em>A Sea of Red. Remember to restart the server when you make configuration changes or you may not see the changes.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ ELI5 Full Stack Basics: breakthrough with Django & EmberJS ]]>
                </title>
                <description>
                    <![CDATA[ By Michael Xavier Welcome to ELI5 Full Stack: Breakthrough with Django & EmberJS. This is an introduction to full stack development for everyone, especially beginners. We’ll go step-by-step through the development of a basic web application. A librar... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/eli5-full-stack-basics-breakthrough-with-django-emberjs-402fc7af0e3/</link>
                <guid isPermaLink="false">66d46040d7a4e35e38434993</guid>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ember ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 18 Sep 2018 23:04:23 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*-YXdpMxaFFkY2QKdxgIsFQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Michael Xavier</p>
<p>Welcome to <strong><em>ELI5 Full Stack: Breakthrough with Django &amp; EmberJS</em></strong>. This is an introduction to full stack development for everyone, especially <strong>beginners</strong>. We’ll go step-by-step through the development of a basic web application. A library of sorts. Together we’ll build a back-end to store data and a RESTful API to manage it. Then we’ll construct a front-end user interface for users to view, add, edit, and delete the data.</p>
<p>This isn’t meant to be a deep dive into either <strong>Django</strong> or <strong>EmberJS</strong>. I don’t want us to get bogged down with too much complexity. <strong>Rather its purpose is to show the critical elements of basic full stack development</strong>. How to stitch together the back end and front end into a working application. I’ll go into detail about the software, frameworks, and tools used in the process. Every terminal command run and line of code in the final application is present in this tutorial.</p>
<p>I’ve kept each section short and to the point so that no one’s head explodes. There are also indicators to mark points for reflection so you can go back and look at what we’ve done and save state. If you don’t know what something means click through to the linked articles which will explain in detail. Remember, this is as an introduction to everyone including <strong>beginners</strong>. If you don’t need the hand holding push on through to the sections relevant to you.</p>
<p>If you’re a beginner, I that suggest you write every line of code and run each terminal command yourself. Don’t copy and paste. It won’t sink in. Take your time and think about what you’re doing. This is a critical trait of an effective and self-sufficient programmer. You will develop this over time if you write your own code and think about what you’re writing. If you mess up (look at my commit history, I definitely did) don’t sweat it. Go back. This isn’t a race. You’ll be fine if you take your time.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/A4ayt-UmztcellrLe6SvphBGHrsHz1u1IXMk" alt="Image" width="800" height="600" loading="lazy">
<em>Sometimes I get whiplash</em></p>
<p><strong>Note</strong>: I developed this tutorial on a MacBook Pro running <a target="_blank" href="https://www.macrumors.com/roundup/macos-10-13/">macOS High Sierra (10.3.6)</a>. I’m using <a target="_blank" href="https://www.iterm2.com/">iTerm2</a> for the terminal and <a target="_blank" href="https://www.sublimetext.com/3">Sublime Text 3</a> as my text editor. All testing uses the <a target="_blank" href="https://www.google.com/chrome/">Chrome</a> browser and its built-in tools. The actual code shouldn’t have any differences. You can <a target="_blank" href="https://github.com/lookininward/my_library"><strong>download the final project files from the Github repository</strong></a>.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<h4 id="heading-section-1-the-whats-hows-and-whys"><strong>Section 1: The Whats, Hows, and Whys</strong></h4>
<p>1.1 Why I Wrote This Tutorial<br>1.2 Back End, Front End. What’s the Difference?<br>1.3 The Concept: A Basic Library Application<br>1.4 Project Directory Structure<br>1.5 Project Directory Setup<br>1.6 Conclusion</p>
<h4 id="heading-section-2-diving-into-the-back-end">Section 2: Diving into the Back End</h4>
<p>2.1 Install Required Software<br>2.2 Start a Django Project: server<br>2.3 Start a Django App: books<br>2.4 Describe the Book model<br>2.5 Register the Book model with the admin<br>2.6 Conclusion</p>
<h4 id="heading-section-3-build-a-server-then-rest">Section 3: Build a Server, then REST</h4>
<p>3.1 Django REST Framework<br>3.2 Create the books API folder<br>3.3 Create a book serializer<br>3.4 Create a view to GET and POST books data<br>3.5 Create URLs to access books data<br>3.6 Conclusion</p>
<h4 id="heading-section-4-laying-down-front-end-foundations">Section 4: Laying Down Front-end Foundations</h4>
<p>4.1 Install Required Software<br>4.2 Start an Ember Project: client<br>4.3 Displaying books data<br>4.4 The books route<br>4.5 Displaying real data in the books route<br>4.6 Conclusion</p>
<h4 id="heading-section-5-correct-data-formats-deal-with-individual-records"><strong>Section 5: Correct data formats, deal with individual records</strong></h4>
<p>5.1 Install the Django REST Framework JSON API<br>5.2 Working with individual book records<br>5.3 The book route<br>5.4 Conclusion</p>
<h4 id="heading-section-6-functional-front-end">Section 6: Functional Front end</h4>
<p>6.1 Adding a new book to the database<br> 6.2 Deleting a book from the database<br>6.3 Editing a book in the database<br>6.4 Conclusion</p>
<h4 id="heading-section-7-moving-on">Section 7: Moving On</h4>
<p>7.1 What’s Next?<br>7.2 Further Reading</p>
<h3 id="heading-section-1-the-whats-hows-and-whys-1">Section 1: The Whats, Hows, and Whys</h3>
<h3 id="heading-11-why-i-wrote-this-tutorial">1.1 Why I Wrote This Tutorial</h3>
<p>Imagine that you’ve recently joined a new company. They’ve been in business for some time, and their major products are already out in production. Think of the application you see today as cake. The process of picking the ingredients, recipe, and putting it all together… well that’s long over. You’ll be working on pieces of that finished cake.</p>
<p>The developers at the start of a project have laid down certain configurations. These change and conventions are also developed over time as developers come and go. By the time you arrive it may be difficult to comprehend how we’ve gotten to where we are. This was my situation. I felt that dipping into the whole stack would be the only way for me to feel comfortable. It would help me understand where we came from and how to move forward with the software we’re building.</p>
<p>This tutorial is the culmination of my experiences as a junior software developer. I’ve been learning a lot at my time with <a target="_blank" href="http://we%27re%20hiring%20now%20so%20feel%20free%20to%20get%20in%20touch%21/">Closing Folders</a>. It represents a shift in my thinking as I take steps towards more complex full stack development. It also serves as an entry point for developers at the stage where they’re wondering how the cake gets baked. I hope this tutorial is as useful for you as it was instructive for me to create.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ReFm2Fb6XzpWqD5x8fDDWipgkDicy7WfarFg" alt="Image" width="666" height="579" loading="lazy">
<em>That wholesome feeling</em></p>
<p><strong>Note</strong>: In a typical workflow a developer would start on the back end to set up the database, and create a REST API. Then, they would work on the front end and build the user interface. Things aren’t so simple though. We make mistakes and often have to go back and forth to resolve them. The jumping back and forth will help build more connections in your mind. and help you better understand how all the pieces fit together. Embrace your mistakes. You’ll be making a lot of them!</p>
<p><strong>Note2</strong>: Attention Senior Devs, Junior Devs, and Designers! [Closing Folders](http://We're hiring now so feel free to get in touch!) is hiring now so feel free to get in touch.</p>
<h3 id="heading-12-back-end-front-end-whats-the-difference">1.2 Back End, Front End. What’s the Difference?</h3>
<p>Back-end development. Front-end development. Full-stack development. So much development... What’s the difference anyway?</p>
<p>Think of front-end development as the part of the application that you see and interact with. For example, the user interface is part of the front end. That’s where the user views data and interacts with it.</p>
<p>Back-end development is everything that stores and serves data. Think about what happens when you login to Medium. None of your user profile data or stories exists on the front end. It’s stored and served from the back end.</p>
<p>The front end and back end work together to form the application. The back end has the instructions for how to store and serve the data. The front end has the instructions to capture the data, and how to display it.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/qD5LLIeEVVXSlKjIuqV2OJspW-Sxlu-YSNX4" alt="Image" width="800" height="463" loading="lazy">
<em>Basic front-end and back-end communication.</em></p>
<p>Find out more about the differences in <a target="_blank" href="http://blog.teamtreehouse.com/i-dont-speak-your-language-frontend-vs-backend">this article</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/kysaEsRUJ593f1PnOYBlVm1W2UOjl9UX4CnJ" alt="Image" width="500" height="334" loading="lazy">
<em>MFW I realized development never actually ends</em></p>
<h3 id="heading-13-the-concept-a-basic-library-application">1.3 The Concept: A Basic Library Application</h3>
<p>Before we start building anything, let’s outline our plans and what we’re trying to achieve. We want to build a <a target="_blank" href="https://stackoverflow.com/a/8694944/5513243">web application</a> called <strong>my_library</strong> that runs in the browser. The application is exactly what it sounds like, a digital library of books. We won’t be dealing with actual book content though. The books will only have title, author, and description information. Keeping it simple.</p>
<p>The application will have the following functionality:</p>
<ul>
<li>View all books as a single list on the home page, ordered by title</li>
<li>View each book in detail, displaying its title, author, and description</li>
<li>Add a new book with the fields title, author, and description</li>
<li>Edit an existing book’s title, author, and description fields</li>
<li>Delete an existing book</li>
</ul>
<h4 id="heading-131-mylibrarys-final-design-and-functionality">1.3.1 my_library’s final design and functionality</h4>
<p>Take a look at the screenshots below. They depict the application’s final look and functionality:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OfA6C6cfPUhNSjp6GhZy3N2gXD6UyRhOm5GZ" alt="Image" width="800" height="695" loading="lazy">
<em>View all the books in our database as a single list ordered by title.</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/E0AxS4kV57E1jZegwU599JK3Mre18RUt2C0Z" alt="Image" width="800" height="695" loading="lazy">
<em>Click on a book to see a detailed view with author and description information.</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ris6Kqmw0lMqDzocS3T72WpXJpBxovfoV0Jy" alt="Image" width="800" height="695" loading="lazy">
<em>Add a new book to the database with the fields title, author, and description.</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/8Vx8NrPBH7ae-u0LG8tzT8QZGSHmmaU8MN0R" alt="Image" width="800" height="695" loading="lazy">
<em>Edit an existing book’s title, author, and description fields.</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/XOuou7IuqqxrlNSU5DdADIxx-gISjjnyn42l" alt="Image" width="800" height="695" loading="lazy">
<em>Confirm deletion of an existing book.</em></p>
<h3 id="heading-14-project-directory-structure">1.4 Project Directory Structure</h3>
<p>There are innumerable ways to structure a given project. I’ll keep everything under one <code>my_library</code> folder for simplicity’s sake like so:</p>
<pre><code>my_library
  - server
    - server
    - books
      - api
    - db.sqlite3
    - manage.py
  - client
    - app
      - adapters
      - controllers
      - models
      - routes
      - templates
      - styles
      router.js
</code></pre><p>These aren’t all the folders and files that the project will contain, though they’re the main ones. You’ll notice quite a few autogenerated files that you can ignore. Though it would be useful for you to read documentation that explains their purpose.</p>
<p>The <code>my_library</code> directory contains folders for the back end and front end sub-projects. <code>server</code> refers to the Django back end, and <code>client</code> refers to the EmberJS front end.</p>
<h4 id="heading-141-back-end">1.4.1 Back End</h4>
<ul>
<li><code>server</code> contains another folder called <code>server</code>. Inside are the top level configurations and settings for the back end.</li>
<li>The <code>books</code> folder will contain all the models, views, and other configuration for the book data.</li>
<li>Inside the <code>books/api</code> folder we’ll create the serializers, URLs, and views that make up our REST API.</li>
</ul>
<h4 id="heading-142-front-end">1.4.2 Front End</h4>
<ul>
<li><code>client</code> is our EmberJS front end. It contains routes, templates, models, controllers, adapters, and styles. <code>router.js</code> describes all the application routes.</li>
</ul>
<p>Let’s go ahead and set up the main project directory <code>my_library</code>.</p>
<h3 id="heading-15-project-directory-setup">1.5 Project Directory Setup</h3>
<h4 id="heading-151-create-the-main-project-folder-mylibrary">1.5.1 Create the main project folder: my_library</h4>
<p>Now that we know what we’re going to build, let’s take a few minutes to set up the main project directory <code>my_library</code>:</p>
<pre><code># cd into desktop and create the main project folder
  cd ~/desktop &amp;&amp; mkdir my_library
</code></pre><p>Create a basic <code>README.md</code> file inside the folder with the following content:</p>
<pre><code># my_library
This is a basic full stack library application built. Check out the tutorial: <span class="hljs-string">'ELI5 Full Stack: Breakthrough with Django &amp; EmberJS'</span>.
</code></pre><p>Now let’s commit this project to a new Git repository as the project start point.</p>
<h4 id="heading-152-install-git-for-version-control">1.5.2 Install Git for version control</h4>
<p>Git is version control software. We’ll use it to keep track of our project and save our state step-by-step so we can always go back if we make breaking errors. I’m sure most of you’re already familiar with it.</p>
<p>For the uninitiated, you can find out more <a target="_blank" href="https://git-scm.com/about">here</a>. If you don’t have Git installed, you can download it <a target="_blank" href="https://git-scm.com/download/mac">here</a>.</p>
<p>Check that it installed with:</p>
<pre><code>$ git --version
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/KApRH2jTbtKv40ejPFGjr54s8hGPoH9YefFD" alt="Image" width="200" height="84" loading="lazy"></p>
<h4 id="heading-153-create-a-new-project-repository">1.5.3 Create a new project repository</h4>
<p>I have an account with <a target="_blank" href="https://github.com/">Github</a>. It’s popular and works well so that’s what I’ll be using. Feel free to use other solutions if they suit you better.</p>
<p>Create a new repository and get the remote URL which should look like this:</p>
<pre><code>git@github.com:username/repo_name.git
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/qbjGYbQ9czlLwNvoMw5JwaOmU9jRFD3dDyn7" alt="Image" width="200" height="53" loading="lazy"></p>
<h4 id="heading-154-commit-and-push-your-changes-to-the-project-repository">1.5.4 Commit and push your changes to the project repository</h4>
<p>Inside the <code>my_library</code> folder initialize the empty repository:</p>
<pre><code>git init
</code></pre><p>Now <a target="_blank" href="https://help.github.com/articles/adding-a-remote/">add the remote URL</a> so Git knows where we’re pushing our files to:</p>
<pre><code>git remote add origin git@github.com:username/repo_name.git
# check that it<span class="hljs-string">'s been set, should display the origin
  git remote -v</span>
</code></pre><p>Time to push our code to Github:</p>
<pre><code># check the status <span class="hljs-keyword">of</span> our repo
# should show the <span class="hljs-keyword">new</span> file README.md, no previous commits
  git status
# add all changes
  git add .
# create a commit <span class="hljs-keyword">with</span> a message
  git commit -m <span class="hljs-string">"[BASE] Project Start"</span>
# push changes to the repo<span class="hljs-string">'s master branch
  git push origin master</span>
</code></pre><p>The remote Git repository updates with the changes we’ve pushed:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jNsMz7ixvdfL8iXHX-g5D8Q7Ov0OptROPTVW" alt="Image" width="800" height="625" loading="lazy"></p>
<p>Now that we have a main project directory and a repository we can finally start working on our back end!</p>
<p><strong>NOTE</strong>: From this point onward I won’t be going into any more detail about commits. The <strong>review and commit indicator below</strong> will let you know when it’s a good time to do so:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/o4SwOn9IR02bwppfcmoKRBV2iujutkGXN8e4" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-16-conclusion">1.6 Conclusion</h3>
<p>We’ve come to the end of <strong>Section 1</strong> with the following steps completed:</p>
<ul>
<li>Got a feel for what we’re building and how it will work</li>
<li>Created the <code>my_library</code> main project directory</li>
<li>Installed <code>git</code> and created a remote project repository on Github</li>
<li>Initialized the local repository and set the remote URL</li>
<li>Created a<code>README.md</code> file, then committed and pushed all changes</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/oMqTTVH075JVrjgb8mj56cKWDPBEfogE5Pea" alt="Image" width="598" height="414" loading="lazy">
<em>Puppy is proud of you</em></p>
<h3 id="heading-section-2-diving-into-the-back-end-1">Section 2: Diving into the Back End</h3>
<p>This section is all about back-end development with Django. We’ll begin with the installation of the required software.</p>
<p>Next, we’ll move onto the creation of a new Django project called <code>server</code> and create a new app called <code>books</code>. In the <code>books</code> app we describe the <code>Book</code> model and register the model with the admin.</p>
<p>Once we create a <code>Superuser</code> account we can login to the Django Admin site. We’ll use the Django Admin site to administrate the database and start seeding it with book data.</p>
<h3 id="heading-21-install-required-software">2.1 Install Required Software</h3>
<p>Before we begin our back end project we’ll need to install some software:</p>
<ul>
<li><a target="_blank" href="https://www.python.org/doc/essays/blurb/">Python</a></li>
<li><a target="_blank" href="https://pip.pypa.io/en/latest/installing/#installing-with-get-pip-py">pip</a></li>
<li><a target="_blank" href="https://virtualenv.pypa.io/en/stable/installation/">virtualenv</a></li>
<li><a target="_blank" href="https://docs.djangoproject.com/en/1.11/topics/install/">Django</a></li>
</ul>
<h4 id="heading-211-python">2.1.1 Python</h4>
<p>If your MacOS is up-to-date it likely already has <code>Python 2.7</code> installed. Feel free to use either <code>2.7</code> or <code>3.x</code>. They’re the same for the purposes of this tutorial.</p>
<p>Installation is simple. <a target="_blank" href="https://www.python.org/downloads/">Download the installer</a> and install as you would a typical MacOS application. Open up the terminal and check that it’s installed:</p>
<pre><code>python --version
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/KN6ZDc46wNzVcEH1yPRUr3ty4fL8wuh6loJV" alt="Image" width="196" height="58" loading="lazy"></p>
<h4 id="heading-212-pip">2.1.2 pip</h4>
<p>In simple terms, pip (Pip Installs Packages) is a package management system. It’s used to install and manage software packages written in Python. In the terminal:</p>
<pre><code># cd into the desktop
  cd ~/desktop

# download the pip Python script
  curl https:<span class="hljs-comment">//bootstrap.pypa.io/get-pip.py -o get-pip.py</span>

# run the script
  python get-pip.py
# once installation completes, verify that it<span class="hljs-string">'s installed
  pip —-version</span>
</code></pre><p>Full installation documentation is available <a target="_blank" href="https://pip.pypa.io/en/latest/installing/#installing-with-get-pip-py">here</a>.</p>
<h4 id="heading-213-virtualenv">2.1.3 virtualenv</h4>
<p>virtualenv is a ‘<em>tool to create isolated Python environments’.</em> These environments have their own installation directories. They don’t share libraries with others. Such silos protect the globally installed libraries from unwanted changes.</p>
<p>With it we can play with Python libraries without messing up the global environment. For example, you install <code>exampleSoftware 1.0</code> on your computer. With a virtual environment activated you can upgrade to <code>exampleSoftware 1.2</code> and use it. This won’t affect the global install of <code>exampleSoftware 1.0</code> at all.</p>
<p>For the development of a particular app you may want to use <code>1.2</code> and for other contexts <code>1.0</code> will be appropriate. Virtual environments give us the ability to separate these contexts. Full installation documentation is available <a target="_blank" href="https://virtualenv.pypa.io/en/stable/installation/">here</a>.</p>
<p>Now, open up the terminal to install virtualenv:</p>
<pre><code># use pip to install virtualenv
  pip install virtualenv
# verify that it<span class="hljs-string">'s installed
  virtualenv —-version</span>
</code></pre><p>Let’s create a directory to house our virtual environments:</p>
<pre><code># cd into the root directory
  cd ~/
# create a hidden folder called .envs <span class="hljs-keyword">for</span> virtual environments
  mkdir .envs
# cd into the virtual environments directory
  cd .envs
</code></pre><p>We can now create a virtual environment for our project:</p>
<pre><code># create a virtual environment folder: my_library
  virtualenv my_library
# activate the virtual environment <span class="hljs-keyword">from</span> anywhere using
  source ~<span class="hljs-regexp">/.envs/my</span>_library/bin/activate
</code></pre><p>Now that we’ve created a virtual environment called <code>my_library</code> there are a few rules to keep in mind. <strong>Make sure the environment is always activated before installing, or updating any packages.</strong></p>
<p>Finally, take a moment to upgrade pip inside this virtual environment:</p>
<pre><code>pip install -U pip
</code></pre><h4 id="heading-214-django-111-lts">2.1.4 Django 1.11 (LTS)</h4>
<p>Django is a web framework that ‘<em>encourages rapid development and clean, pragmatic design…’</em></p>
<p>It provides us with a set of common components so we don’t have to reinvent everything from scratch.</p>
<p>Examples include:</p>
<ul>
<li>a management panel</li>
<li>a way to handle user authentication</li>
</ul>
<p>Checkout out <a target="_blank" href="https://tutorial.djangogirls.org/en/django/">this DjangoGirls article</a> to learn more about Django and why it’s used.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/xTQRhumtGS8zEEkoz6pjawMTmfHTJBYDzmJd" alt="Image" width="200" height="91" loading="lazy"></p>
<p>In this project we’ll be using Django to handle the back end. Along with its add-ons, Django provides the basic tools to develop a REST API.</p>
<pre><code># inside my_library <span class="hljs-keyword">with</span> virtualenv activated
  pip install Django==<span class="hljs-number">1.11</span>
# verify that it<span class="hljs-string">'s installed, open up the Python shell
  python
# access the django library and get the version (should be 1.11)
  import django
  print(django.get_version())
# exit using keyboard shortcut ctrl+D or:
  exit()</span>
</code></pre><p>Full installation documentation is available <a target="_blank" href="https://docs.djangoproject.com/en/1.11/topics/install/">here</a>.</p>
<h3 id="heading-22-start-a-django-project-server">2.2 Start a Django Project: server</h3>
<p>Let’s use the <a target="_blank" href="https://docs.djangoproject.com/en/2.1/ref/django-admin/">django-admin</a> to generate a new Django project. This is Django’s ‘<em>command-line utility for administrative tasks</em>’:</p>
<pre><code># cd into the project folder
  cd ~<span class="hljs-regexp">/desktop/my</span>_library
# initialize the virtual environment
  source ~<span class="hljs-regexp">/.envs/my</span>_library/bin/activate
# use Django to create a project: server
  django-admin startproject server
# cd into the <span class="hljs-keyword">new</span> Django project
  cd server
# synchronize the database
  python manage.py migrate
# run the Django server
  python manage.py runserver
</code></pre><p>Now visit <code>http://localhost:8000</code> in your browser and confirm that the Django project is working:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7i6tTqE67PlSVFaTr9cp64isfajFSzMzFehh" alt="Image" width="800" height="141" loading="lazy">
<em>Server running. Success!</em></p>
<p>You can shut down the server with <code>cmd+ctrl</code>.</p>
<h4 id="heading-221-create-the-superuser-account">2.2.1 Create the Superuser account</h4>
<p>We’ll have to create a <a target="_blank" href="https://docs.djangoproject.com/en/1.11/ref/django-admin/#createsuperuser">superuser</a> to login to the admin site and handle database data. Inside <code>my_library/server</code> we run:</p>
<pre><code># create superuser
  python manage.py createsuperuser
</code></pre><p>Fill in the fields <code>Username</code>, <code>Email Address</code> (optional), and <code>Password</code>. You should receive a success message.</p>
<p>Now run the server with <code>python manage.py runserver</code> and go to <code>localhost:8000/admin</code> to see the admin login page. Enter your superuser account details to login.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/o1Gki-a2KqtXWP15qNmcEomH8Zo8lpMzxkk-" alt="Image" width="800" height="204" loading="lazy">
<em>Logged into the Django Admin site</em></p>
<p>Nice! We have access to the Django admin site. Once we create the <code>books</code> model and do the appropriate setup we’ll be able to add, edit, delete, and view book data.</p>
<p>Logout and shut down the server with <code>cmd+ctrl</code>.</p>
<h4 id="heading-222-protecting-our-secrets">2.2.2 Protecting Our Secrets</h4>
<p>Before moving on, we’ll want to update the settings.py file. It contains authentication credentials that we don’t want to expose to the public. We’ll want to keep these credentials out of our remote repository. There are many <a target="_blank" href="https://medium.freecodecamp.org/how-to-securely-store-api-keys-4ff3ea19ebda">ways of protecting ourselves.</a> This is my approach to it:</p>
<pre><code># create a config.json file to hold our configuration values
  my_library/server/server/config.json
</code></pre><p>Inside we’ll store our <code>SECRET_KEY</code> value from <code>settings.py</code> under <code>API_KEY</code>:</p>
<pre><code>{
  <span class="hljs-string">"API_KEY"</span> : <span class="hljs-string">"abcdefghijklmopqrstuvwxyz123456789"</span>
}
</code></pre><p>In <code>settings.py</code> import the <code>json</code> library and load the config variables:</p>
<pre><code class="lang-py"><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> json
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
<span class="hljs-keyword">with</span> open(BASE_DIR + <span class="hljs-string">'/server/config.json'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> config:
    obj = json.load(config)
SECRET_KEY = obj[<span class="hljs-string">"API_KEY"</span>]
...
</code></pre>
<p>So that <code>config.json</code> (with the secret key) isn’t pushed to the repository, create a <code>.gitignore</code> file in <code>my_library</code>. This ignores it (along with some other autogenerated files and the database):</p>
<pre><code>### Django ###
config.json
*.log
*.pot
*.pyc
__pycache__/
local_settings.py
db.sqlite3
media
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/gdH03DpyBNSsAOwSThZDMwnkkM8LFI0DIoyQ" alt="Image" width="610" height="343" loading="lazy"></p>
<p>Now when you commit the changes the files and folders listed above aren’t added. Our secrets are safe and our repo won’t contain unnecessary extra files!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/unF2nV9ydWZI5ueW1dOY5nrSbkGBObGUe48x" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-23-start-a-django-app-books">2.3 Start a Django App: books</h3>
<p>Think of Django apps as modules that plugin into your project. We’ll create an app called <code>books</code> containing the models, views, and other settings. This is how we interact with the books data in the database.</p>
<p>What are the differences between projects and apps in Django? Check out <a target="_blank" href="https://stackoverflow.com/questions/19350785/what-s-the-difference-between-a-project-and-an-app-in-django-world">this thread</a>.</p>
<pre><code># create <span class="hljs-keyword">new</span> app: books
  python manage.py startapp books
# creates directory: my_library/server/books
</code></pre><p>Now we’ll install the <code>books</code> app into the <code>server</code> project. Open the settings file: <code>my_library/server/server/settings.py</code>.</p>
<p>Scroll to the <code>INSTALLED_APPS</code> array. Django has installed it's own core apps by default. Install the <code>books</code> app at the end of the array:</p>
<pre><code>INSTALLED_APPS = [
  ...
  <span class="hljs-string">'books'</span>
]
</code></pre><h3 id="heading-24-describe-the-book-model">2.4 Describe the Book model</h3>
<p>Next we describe the <code>Book</code> model in the books app. Open the models file <code>my_library/server/books/models.py</code>.</p>
<p>Describe a <code>Book</code> model which tells Django that every book in the database will have:</p>
<ul>
<li>a <code>title</code> field up to 500 characters in length</li>
<li>an <code>author</code> field up to 100 characters</li>
<li>a <code>description</code> field with an open-ended number of characters</li>
</ul>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>(<span class="hljs-params">models.Model</span>):</span>
  title       = models.CharField(max_length=<span class="hljs-number">500</span>)
  author      = models.CharField(max_length=<span class="hljs-number">100</span>)
  description = models.TextField()
</code></pre>
<h3 id="heading-25-register-the-book-model-with-the-admin">2.5 Register the Book model with the admin</h3>
<p>Now we register the <code>Book</code> model with the admin for our <code>books</code> app. This lets us view it in the admin site and manipulate the books data from there. Open the admin file <code>my_library/server/books/admin.py</code> and add:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Book

<span class="hljs-meta">@admin.register(Book)</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">bookAdmin</span>(<span class="hljs-params">admin.ModelAdmin</span>):</span>
  list_display = [<span class="hljs-string">'title'</span>, <span class="hljs-string">'author'</span>, <span class="hljs-string">'description'</span>]
</code></pre>
<p>With a new model created we’ll have to make and run <a target="_blank" href="https://docs.djangoproject.com/en/2.1/ref/django-admin/#django-admin-makemigrations">migrations</a> so that the database synchronizes:</p>
<pre><code>python manage.py makemigrations
python manage.py migrate
</code></pre><p>Run the server and go to <code>localhost:8000/admin</code> to login. Notice that the Book model registered with the admin displays:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/BByc9ryhPWVpc6U4SWpaz3E6JTrOeFcQcwFB" alt="Image" width="800" height="271" loading="lazy">
<em>With the ‘Book’ model registered with the admin</em></p>
<p>Clicking on ‘Books’ displays an empty list because there are no books in the database. Click ‘Add’ to begin creating a new book to add to the database. Go ahead and create a few books.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/g24EmlIIvatYfhwIRgzXi3yakh8MzCJnnxfo" alt="Image" width="800" height="462" loading="lazy">
<em>Add a new book to the database</em></p>
<p>Save and go back to the list to view the new data. Now it displays the title, author, and description (<code>list_display array</code>) fields.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jnqaPh1DSeqpT2wrzeA9bppZRhWcVM3Z4O21" alt="Image" width="800" height="450" loading="lazy">
<em>List of all the books we’ve added to the database</em></p>
<p>This is great. We can now view our database books in the admin site. Create, edit, and delete functions are also available.</p>
<p><strong>Note</strong>: For simplicity’s sake we’ll use the <a target="_blank" href="https://www.sqlite.org/about.html">SQLite database.</a> It comes preinstalled with the creation of every Django project. No need to do any extra work with databases for the purposes of this tutorial.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/vMyJyhv4xHSQNKh3IkRdoJvFKtO5Olet5iQz" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-26-conclusion">2.6 Conclusion</h3>
<p>Congrats, we made it to the end of <strong>Section 2</strong>! This is what we’ve done so far:</p>
<ul>
<li>Installed <code>python</code></li>
<li>Used <code>python</code> to install the <code>pip</code> package manager</li>
<li>Used <code>pip</code> to install <code>virtualenv</code> to create virtual environments</li>
<li>Created a virtual environment in <code>~/.envs</code> called <code>my_library</code></li>
<li>Activated the <code>my_library</code> environment and upgraded <code>pip</code></li>
<li>Installed <code>Django 1.11 LTS</code> within the <code>my_library</code> environment</li>
<li>Created our project directory <code>my_library</code></li>
<li>Created the Django project <code>server</code></li>
<li>Created a <code>Superuser</code> account to access the Django admin site</li>
<li>Protected our secrets by moving our <code>SECRET_KEY</code> into <code>config.json</code></li>
<li>Ignored autogenerated and/or sensitive files with <code>.gitignore</code></li>
<li>Created a new app called <code>books</code></li>
<li>Described the <code>Book</code> model</li>
<li>Registered the <code>Book</code> model with the admin</li>
<li>Added books data into the database</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-CPsLneURbcGROamQjKRjILkxEgEv5-DNq3o" alt="Image" width="730" height="548" loading="lazy">
<em>That which holds the internet together</em></p>
<h3 id="heading-section-3-build-a-server-then-rest-1">Section 3: Build a Server, then REST</h3>
<p>In this section we use the Django REST Framework to build our <code>books</code> API. It has serializers, views, and URLs that query, structure, and deliver the book data. The data and methods are accessible through API endpoints.</p>
<p>These endpoints are one end of a communication channel. Touchpoints of the communication between the API and another system. The other system in this context is our Ember front end client. The Ember client will interact with the database through the API endpoints. We create these endpoints with Django and the Django REST Framework.</p>
<p>We used Django to set up the <code>book</code> model and the admin site that lets us interact with the database. Django REST Framework will help us build the REST API that the front end will use to interact with the back end.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/DRBFIYTjAoZWDNDv9VOK1bWvOIIJej8x5xOP" alt="Image" width="800" height="603" loading="lazy">
<em>Application layers stacked one by one.</em></p>
<h3 id="heading-31-django-rest-framework">3.1 Django REST Framework</h3>
<p><a target="_blank" href="http://www.django-rest-framework.org/">Django REST Framework</a> (DRF) builds on top of Django. It simplifies the creation of <a target="_blank" href="http://rest.elkstein.org/">RESTful Web APIs</a>. It comes with tools to make the process straightforward.</p>
<p>The developers of DRF have identified common patterns for serializers and views. Since our data and what users can do with it are simple, we’ll use the built-in serializers and views. Remember, our book data only has three fields <code>title</code>, <code>author</code>, and <code>description</code>. Users are able create new records of books, edit, and delete existing records. This functionality is well within the range of basic common patterns. They’re well supported by the built-in serializers and views. We won’t have to build these from scratch.</p>
<p>For more complex projects you’ll want to overwrite defaults or make your own. Again, for the purposes of simplicity we’ll use what comes out of the box without undue modification.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/e6SmOCOMO13g05h-y06mLtBMqtAn2is3WxwX" alt="Image" width="153" height="87" loading="lazy"></p>
<h4 id="heading-311-install-django-rest-framework">3.1.1 Install Django REST Framework</h4>
<p>Enter the <code>my_library</code> directory and activate the virtual environment. To start working with DRF, install it with <code>pip</code>:</p>
<pre><code># enter my_library
  cd ~<span class="hljs-regexp">/desktop/my</span>_library

# activate the virtual environment
  source ~<span class="hljs-regexp">/.envs/my</span>_library/bin/activate

# install Django REST Framework
  pip install djangorestframework
# install Markdown support <span class="hljs-keyword">for</span> the browsable API
  pip install markdown
</code></pre><p>Now open up <code>my_library/server/server/settings.py</code>. Install DRF right above the <code>books</code> app in the <code>INSTALLED_APPS</code> array:</p>
<pre><code>INSTALLED_APPS = [
  ...
  <span class="hljs-string">'rest_framework'</span>,
  <span class="hljs-string">'books'</span>
]
</code></pre><p>Add the default settings at the bottom of the file as an object called <code>REST_FRAMEWORK</code>:</p>
<pre><code>REST_FRAMEWORK = {
  <span class="hljs-string">'DEFAULT_PERMISSION_CLASSES'</span>: [      
   <span class="hljs-string">'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'</span>
  ]
}
</code></pre><p>The settings object contains a <code>DEFAULT_PERMISSION_CLASSES</code> key with an array. The only item in the array is a permission class. This ‘<em>allows unauthenticated users to have read-only access to the API’</em>. Find out more about permissions <a target="_blank" href="http://www.django-rest-framework.org/api-guide/permissions/#permissions">here</a>.</p>
<h3 id="heading-32-create-the-books-api-folder">3.2 Create the books API folder</h3>
<p>With DRF installed let’s start building the <code>books</code> API. Create a new folder called <code>api</code> inside the <code>books</code> app. Then create an empty <code>__init__.py</code> file within: <code>my_library/server/books/api/__init__.py</code>.</p>
<p>The empty file tells Python that this folder is a Python module. The <code>api</code> folder will contain the serializers, views, and URLs for our books data. I’ll get into the meanings of these terms in their respective sections below.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/teuNGFUsjk6LLyFuKtD-pcN1IwvWwP8o0oh6" alt="Image" width="393" height="330" loading="lazy"></p>
<h3 id="heading-33-create-a-book-serializer">3.3 Create a book serializer</h3>
<p>In simple terms, <a target="_blank" href="http://www.django-rest-framework.org/api-guide/serializers/">serializers</a> take database data and restructure it. This structure is a blueprint for the data to alternate between application layers. It gets the front end and backend to speak to each other in a common language.</p>
<p>For example, the front end we’ll create expects the response returned to it from a request to be in the JSON format. Serializing the data to be in JSON ensures the front end will be able to read and write it.</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> serializers
<span class="hljs-keyword">from</span> books.models <span class="hljs-keyword">import</span> Book
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">bookSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
    model = Book
    fields = (
      <span class="hljs-string">'id'</span>,
      <span class="hljs-string">'title'</span>,
      <span class="hljs-string">'author'</span>,
      <span class="hljs-string">'description'</span>,
    )
</code></pre>
<p>This serializer takes the data and transforms it into the JSON format. This ensures that it’s understandable to the front end.</p>
<h4 id="heading-imports"><strong>Imports</strong></h4>
<p>We import built-in <code>serializers</code> from DRF, and the <code>Book</code> model from our <code>books</code> app.</p>
<pre><code><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> serializers
<span class="hljs-keyword">from</span> books.models <span class="hljs-keyword">import</span> Book
</code></pre><h4 id="heading-the-bookserializer-class"><strong>The bookSerializer Class</strong></h4>
<p>For this project we want a <code>Serializer</code> class that ‘<em>corresponds to the Model fields</em>’. The serializer should map to the model fields <code>title</code>, <code>author</code>, and <code>description</code>. We can do this with the <code>[ModelSerializer](http://www.django-rest-framework.org/api-guide/serializers/#modelserializer)</code>. According to the documentation:</p>
<p>The <code>ModelSerializer</code> class is the same as a regular <code>Serializer</code> class, except that:</p>
<ul>
<li>It will generate a set of fields for you, based on the model.</li>
<li>It will generate validators for the serializer, such as unique_together validators.</li>
<li>It includes simple default implementations of <code>.create()</code> and <code>.update()</code>.</li>
</ul>
<p>The built-in tools are more than capable of handling our basic needs.</p>
<pre><code class="lang-py"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">bookSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
    model = Book
    fields = (
      <span class="hljs-string">'id'</span>,
      <span class="hljs-string">'title'</span>,
      <span class="hljs-string">'author'</span>,
      <span class="hljs-string">'description'</span>,
    )
</code></pre>
<h3 id="heading-34-create-a-view-to-get-and-post-books-data">3.4 Create a view to GET and POST books data</h3>
<p>View functions take in a web request and return web responses. A web request to <code>localhost:8000/api/books</code> for example elicits a response from the server.</p>
<p>This response can be ‘<em>HTML contents of a Web page, or a redirect, or a 404 error, or an XML document, or an image . . . or anything…</em>’ In our case we expect to get back books data structured in the JSON format.</p>
<p>Create the views file in <code>my_library/server/books/api/views.py</code>:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics, mixins
<span class="hljs-keyword">from</span> books.models <span class="hljs-keyword">import</span> Book
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span>  bookSerializer
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">bookAPIView</span>(<span class="hljs-params">mixins.CreateModelMixin, generics.ListAPIView</span>):</span>
  resource_name = <span class="hljs-string">'books'</span>
  serializer_class = bookSerializer
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_queryset</span>(<span class="hljs-params">self</span>):</span>
    <span class="hljs-keyword">return</span> Book.objects.all()
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span>(<span class="hljs-params">self, request, *args, **kwargs</span>):</span>
    <span class="hljs-keyword">return</span> self.create(request, *args, **kwargs)
</code></pre>
<h4 id="heading-imports-1"><strong>Imports</strong></h4>
<p>First we import <code>[generics](http://www.django-rest-framework.org/api-guide/generic-views/#genericapiview)</code> and <code>[mixins](http://www.django-rest-framework.org/api-guide/generic-views/#mixins)</code> from DRF. Then the <code>Book</code> model from our <code>books</code> app and the <code>bookSerializer</code> that we created.</p>
<p><code>generics</code> refers to API views that ‘<em>map to your database models</em>’. These are ‘<em>pre-built views that provide for common patterns</em>’. <code>mixins</code> are classes that ‘<em>provide the actions that used to provide the basic view behavior</em>’. Our book model is simplistic. It only has <code>title</code>, <code>author</code>, and <code>description</code> attributes so these provide us with the basics we need.</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics, mixins
<span class="hljs-keyword">from</span> books.models <span class="hljs-keyword">import</span> Book
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span>  bookSerializer
</code></pre>
<h4 id="heading-the-bookapi-view"><strong>The bookAPI View</strong></h4>
<p>We then create a <code>bookAPIView</code> which takes in the <code>[CreateModelMixin](http://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin)</code> and <code>[ListAPIView](http://www.django-rest-framework.org/api-guide/generic-views/#listapiview)</code>.</p>
<p><code>CreateModelMixin</code> provides a <code>.create(request, *args, **kwargs)</code> method<em>.</em> This implements the creation and persistence of a new model instance. When successful it returns a <code>201 Create</code> response. This comes with a serialized representation of the object that it created.</p>
<p>For example, we would make a POST request to create a new book record for the Steve Jobs book by Walter Isaacson. If successful we get back a response with the code <code>201</code>. The serialized representation of the book record like so:</p>
<pre><code class="lang-py">{
  <span class="hljs-string">"data"</span>: {
    <span class="hljs-string">"type"</span>: <span class="hljs-string">"books"</span>,
    <span class="hljs-string">"id"</span>:<span class="hljs-string">"10"</span>,
    <span class="hljs-string">"attributes"</span>: {
      <span class="hljs-string">"title"</span>: <span class="hljs-string">"Steve Jobs"</span>,
      <span class="hljs-string">"author"</span>: <span class="hljs-string">"Walter Isaacson"</span>,
      <span class="hljs-string">"description"</span>: <span class="hljs-string">"Based on more than forty interviews with Jobs conducted over two years—as..."</span>
    }
  }
}
</code></pre>
<p>When unsuccessful, we’ll get back a <code>400 Bad Request</code> response with errors details. For example, if we try to create a new book record but don’t provide any <code>title</code> information:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"errors"</span>:[
    {
      <span class="hljs-attr">"status"</span>: <span class="hljs-string">"400"</span>,
      <span class="hljs-attr">"source"</span>: {
        <span class="hljs-attr">"pointer"</span>: <span class="hljs-string">"/data/attributes/title"</span>
      },
      <span class="hljs-attr">"detail"</span>: <span class="hljs-string">"This field may not be blank."</span>
    }
  ]
}
</code></pre>
<p><code>ListAPIView</code> serves our read-only endpoints (GET). It represents ‘<em>a collection of model instances</em>’. We use it when we want to get all or many books.</p>
<p><code>bookAPIView</code> also takes in the recently created <code>bookSerializer</code> for its <code>serializer_class</code>.</p>
<p>We set the <code>resource_name</code> to ‘books’ to ‘<em>specify the</em> <em>type</em> <em>key in the json output</em>’. The front end client data store layer will have a <code>book</code> model that is case sensitive. We don’t want to <code>book</code> model in Ember and the <code>Book</code> model in Django to clash. Setting the <code>resource_name</code> here nips that issue in the bud.</p>
<pre><code class="lang-py"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">bookAPIView</span>(<span class="hljs-params">mixins.CreateModelMixin, generics.ListAPIView</span>):</span>
  resource_name = <span class="hljs-string">'books'</span>
  serializer_class = bookSerializer
</code></pre>
<h4 id="heading-functions"><strong>Functions</strong></h4>
<p>The function <code>get_queryset</code> returns all the book objects in the database. <code>post</code> takes in the request and arguments and creates a new database record of a book if the request is valid.</p>
<pre><code class="lang-py"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_queryset</span>(<span class="hljs-params">self</span>):</span>
    <span class="hljs-keyword">return</span> Book.objects.all()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span>(<span class="hljs-params">self, request, *args, **kwargs</span>):</span>
    <span class="hljs-keyword">return</span> self.create(request, *args, **kwargs)
</code></pre>
<h3 id="heading-35-create-urls-to-access-books-data">3.5 Create URLs to access books data</h3>
<p>URL patterns map a URL to views. For example, visiting <code>localhost:8000/api/books</code> should map to a URL pattern. That then returns the results of a query to that view.</p>
<p>Create the URLs file in <code>my_library/server/books/api/urls.py</code>:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> .views <span class="hljs-keyword">import</span> bookAPIView
<span class="hljs-keyword">from</span> django.conf.urls <span class="hljs-keyword">import</span> url
urlpatterns = [
  url(<span class="hljs-string">r'^$'</span>, bookAPIView.as_view(), name=<span class="hljs-string">'book-create'</span>),
]
</code></pre>
<h4 id="heading-imports-2"><strong>Imports</strong></h4>
<p>We import our view <code>bookAPIView</code> and <code>url</code>. We’ll use <code>url</code> to create a list of url instances.</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> .views <span class="hljs-keyword">import</span> bookAPIView
<span class="hljs-keyword">from</span> django.conf.urls <span class="hljs-keyword">import</span> url
</code></pre>
<h4 id="heading-booksapi-url-patterns"><strong>booksAPI URL patterns</strong></h4>
<p>In the <code>urlpatterns</code> array we create a URL pattern with the following structure:</p>
<ul>
<li>the pattern <code>r'^$'</code></li>
<li>the Python path to the view <code>bookAPIView.as_view()</code></li>
<li>the name <code>name='book-create'</code></li>
</ul>
<p>The pattern <code>r’^$’</code>is a regular expression that ‘<a target="_blank" href="https://stackoverflow.com/a/31057541/5513243"><em>matches an empty line/string</em></a>’. This means it matches to <code>localhost:8000</code>. It matches to anything that comes after the base URL.</p>
<p>We call <code>[.as_view()](https://docs.djangoproject.com/en/1.11/ref/class-based-views/base/#django.views.generic.base.View.as_view)</code> on <code>bookAPIView</code> because to connect the view to the url. It ‘<a target="_blank" href="https://stackoverflow.com/a/31491074/5513243"><em>is the function(class method) which will connect [the] class with its url</em></a>’. Visit a particular URL and the server attempts to match it to the URL pattern. That pattern will then return the <code>bookAPI</code> view results that we’ve told it to respond with.</p>
<p>The <code>name=’book-create’</code> attribute provides us with a <code>name</code> attribute. We use it to refer to our URL throughout the project. Let’s say you want to change the URL or the view it refers to. Change it here. Without <code>name</code> we would have to go through the entire project to update every reference. Check out <a target="_blank" href="https://stackoverflow.com/a/11241936/5513243">this thread</a> to find out more.</p>
<pre><code>urlpatterns = [
  url(r<span class="hljs-string">'^$'</span>, bookAPIView.as_view(), name=<span class="hljs-string">'book-create'</span>),
]
</code></pre><h4 id="heading-server-url-patterns"><strong>server URL patterns</strong></h4>
<p>Now let’s open up <code>server</code>’s URLs file <code>my_library/server/server/urls.py</code>:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> django.conf.urls <span class="hljs-keyword">import</span> url, include
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
urlpatterns = [
  url(<span class="hljs-string">r'^admin/'</span>, admin.site.urls),
  url(<span class="hljs-string">r'^api/books'</span>, include(<span class="hljs-string">'books.api.urls'</span>, 
                              namespace=<span class="hljs-string">'api-books'</span>))
]
</code></pre>
<p>Here we import <code>include</code> and create the <code>r’^api/books’</code> pattern which takes in any URLs we created in the <code>api</code> folder. Now the base URL for our <code>books</code> API URLs becomes <code>localhost:8000/api/books</code>. Visiting this URL will match to our <code>r’^/api/books’</code> pattern. This matches to the <code>r’^$’</code> pattern we constructed in the <code>books</code> API.</p>
<p>We use <code>namespace=’api-books’</code> so that the URLs don’t collide with each other. This would happen if they’re named the same in another app we create. Learn more about why we use <code>namespaces</code> in <a target="_blank" href="https://stackoverflow.com/a/19171674/5513243">this thread</a>.</p>
<h4 id="heading-351-demonstration-browsing-the-books-api">3.5.1 Demonstration: Browsing the books API</h4>
<p>Now that we have the base REST framework setup let’s check out the data the back end is returning. With the server running, visit <code>localhost:8000/api/books</code>. The <a target="_blank" href="http://www.django-rest-framework.org/topics/browsable-api/">browsable API</a> should return something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/vRQH7EEhJl7Dt0M8tqtXezjE48ESk1PF4Urv" alt="Image" width="800" height="806" loading="lazy">
<em>Django REST Framework returning book data from the database</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/nhkde41r7VxTDjRtIB0qc-ry3jugObDiqfWE" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-36-conclusion">3.6 Conclusion</h3>
<p>Awesome, we’re getting going now. By the end of <strong>Section 3</strong> we’ve completed the following steps:</p>
<ul>
<li>Installed Django REST Framework into our project</li>
<li>Started building the <code>books</code> API</li>
<li>Created a <code>serializer</code> for books</li>
<li>Created a <code>view</code> for books</li>
<li>Created <code>URLs</code> for books</li>
<li>Browsed the books API that returns book data from the back end</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/QeaabxrQLyzXfW30akDR1qeTrjxVyXUZ4dez" alt="Image" width="800" height="450" loading="lazy">
<em>Gift from the gods</em></p>
<h3 id="heading-section-4-laying-down-front-end-foundations-1">Section 4: Laying Down Front-end Foundations</h3>
<p>In this section we shift our attention to the front end and begin working with the Ember framework. We’ll install the required software, set up a basic DOM, styles, create the <code>book</code> model, and the <code>books</code> route. We’ll also load up fake book data for demonstration purposes before we go on to access real data from the back end.</p>
<h3 id="heading-41-install-required-software">4.1 Install Required Software</h3>
<p>To begin front-end development we need to install some software:</p>
<ul>
<li><a target="_blank" href="https://nodejs.org/en/">Node.js, NPM</a></li>
<li><a target="_blank" href="https://ember-cli.com/">Ember CLI</a></li>
</ul>
<h4 id="heading-411-nodejs-and-npm">4.1.1 NodeJS and NPM</h4>
<p>NodeJS is an open source server environment. We don’t need to get into the details right now. NPM is a package manager for Node.js packages. We use it to install packages like the Ember CLI.</p>
<p>Install NodeJS and NPM using the <a target="_blank" href="http://nodejs.org/en/download/">installation file from the official site</a>.</p>
<p>Once installation is complete check that everything installed:</p>
<pre><code>node --version
npm --version
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/hEqfcvp-GnAp2OUfgwCUCBON6UN0fDoovaJu" alt="Image" width="600" height="200" loading="lazy"></p>
<h4 id="heading-412-ember-cli">4.1.2 Ember CLI</h4>
<p>Let’s use NPM to install the Ember CLI. That’s the ‘<em>official command line utility used to create, build, serve, and test <a target="_blank" href="https://emberjs.com/">Ember.js</a> apps and addons</em>’. Ember CLI comes with all the tools we need to build the front end of our application.</p>
<pre><code># install Ember CLI
  npm install -g ember-cli
# check that it<span class="hljs-string">'s installed
  ember --version</span>
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/6hklopSfXA8qI9ssI6yPxWmES2K2oF40a-Xm" alt="Image" width="220" height="220" loading="lazy"></p>
<h3 id="heading-42-start-an-ember-project-client">4.2 Start an Ember Project: client</h3>
<p>Let’s create a front end client called <code>client</code> using Ember CLI:</p>
<pre><code># cd into the main project folder
  cd ~<span class="hljs-regexp">/desktop/my</span>_library
# create a <span class="hljs-keyword">new</span> app: client
  ember <span class="hljs-keyword">new</span> client
# cd into the directory
  cd client
# run the server
  ember s
</code></pre><p>Head over to <code>http://localhost:4200</code> and you should see this screen:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/9CdYwMxZs608uCFDtckD2hupL4IKrcfI1Ehz" alt="Image" width="800" height="496" loading="lazy">
<em>Up and running</em></p>
<p>The base Ember client project is running as expected. You can shut down the server with <code>ctrl+C</code>.</p>
<h4 id="heading-421-update-gitignore-with-ember-exclusions">4.2.1 Update .gitignore with Ember exclusions</h4>
<p>Before we make any new commits, let’s update the <code>.gitignore</code> file. We want to exclude unwanted files from from the repo. Add on to the file below the Django section:</p>
<pre><code>...
### Ember ###
/client/dist
/client/tmp
# dependencies
/client/node_modules
/client/bower_components
# misc
/client/.sass-cache
/client/connect.lock
/client/coverage<span class="hljs-comment">/*
/client/libpeerconnection.log
/client/npm-debug.log
/client/testem.log
# ember-try
/client/.node_modules.ember-try/
/client/bower.json.ember-try
/client/package.json.ember-try</span>
</code></pre><h3 id="heading-43-displaying-books-data">4.3 Displaying books data</h3>
<h4 id="heading-431-setup-the-dom">4.3.1 Setup the DOM</h4>
<p>Now that we’ve generated a base project, let’s set up a basic DOM and styles. I’m not doing anything fancy here. It’s the least necessary to have our data displaying in a readable format.</p>
<p>Locate the file <code>client/app/templates/application.hbs</code>. Get rid of <code>{{welcome-page}}</code> and the comments .</p>
<p>Next, create a <code>div</code> with the class <code>.nav</code>. Use Ember’s built-in <code>[{{#link-to}}](https://guides.emberjs.com/release/templates/links/)</code> helper to create a link to the route <code>books</code>(we’ll create it later):</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav"</span>&gt;</span>
  {{#link-to 'books' class="nav-item"}}Home{{/link-to}}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Wrap everything including the<code>[{{outlet}}](https://guides.emberjs.com/release/routing/rendering-a-template/)</code> in a <code>div</code> with the <code>.container</code> class. Each route template will render inside <code>{{outlet}}</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav"</span>&gt;</span>
    {{#link-to 'books' class="nav-item"}}Home{{/link-to}}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{{outlet}}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This is the template for the parent level <code>application</code> route. any sub-routes like <code>books</code> will render inside the <code>{{outlet}}</code>. This means that the <code>nav</code> will always be visible on screen.</p>
<h4 id="heading-432-create-styles">4.3.2 Create styles</h4>
<p>I’m not going to get into the nitty-gritty of the CSS. It’s pretty simple to figure out. Locate the file <code>client/app/styles/app.css</code> and add the following styles:</p>
<p><strong>Variables and Utilities</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--color-white</span>:  <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">--color-black</span>:  <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">--color-grey</span>:   <span class="hljs-number">#d2d2d2</span>;
  <span class="hljs-attribute">--color-purple</span>: <span class="hljs-number">#6e6a85</span>;
  <span class="hljs-attribute">--color-red</span>:    <span class="hljs-number">#ff0000</span>;
  <span class="hljs-attribute">--font-size-st</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">--font-size-lg</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">--box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-number">20px</span> -<span class="hljs-number">12px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.42</span>),
                <span class="hljs-number">0</span> <span class="hljs-number">3px</span>  <span class="hljs-number">20px</span>  <span class="hljs-number">0px</span>  <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.12</span>),
                <span class="hljs-number">0</span> <span class="hljs-number">8px</span>  <span class="hljs-number">10px</span> -<span class="hljs-number">5px</span>  <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>);
}
<span class="hljs-selector-class">.u-justify-space-between</span> {
  <span class="hljs-attribute">justify-content</span>: space-between <span class="hljs-meta">!important</span>;
}
<span class="hljs-selector-class">.u-text-danger</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color-red) <span class="hljs-meta">!important</span>;
}
</code></pre>
<p><strong>General</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: Arial;
}
<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-number">40px</span> <span class="hljs-built_in">calc</span>(<span class="hljs-number">100vh</span> - <span class="hljs-number">80px</span>) <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/5XDkBqqpQcV7KXyA9HFpXOMED7ISf-wTnlhR" alt="Image" width="800" height="683" loading="lazy"></p>
<p><strong>Navigation</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.nav</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--color-purple);
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-built_in">var</span>(--box-shadow);
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">10</span>;
}
<span class="hljs-selector-class">.nav-item</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--font-size-st);
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color-white);
  <span class="hljs-attribute">text-decoration</span>: none;
}
<span class="hljs-selector-class">.nav-item</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.1</span>);
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/vNzYqMngN91hTgUYcAqWpW01vkaJDBGTWGJ7" alt="Image" width="800" height="78" loading="lazy"></p>
<p><strong>Headings</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.header</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--font-size-lg);
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/UKbiWepf0IEUTAjL-9JuR8MUa6zO3HxkCpvU" alt="Image" width="494" height="200" loading="lazy"></p>
<p><strong>Books List</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.book-list</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">overflow-y</span>: scroll;
}
<span class="hljs-selector-class">.book</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--font-size-st);
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color-black);
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">cursor</span>: pointer;
}
<span class="hljs-selector-class">.book</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--color-grey);
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/rcfJhkZZS1D0wxCyxIC9X9jc6BkLnsVAMlWJ" alt="Image" width="652" height="444" loading="lazy"></p>
<p><strong>Buttons</strong></p>
<pre><code>button {
  <span class="hljs-attr">cursor</span>: pointer;
}
</code></pre><p><strong>Book Detail</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.book</span><span class="hljs-selector-class">.book--detail</span> {
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: flex-start;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">500px</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--color-white);
  <span class="hljs-attribute">cursor</span>: default;
}
<span class="hljs-selector-class">.book-title</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--font-size-lg);
}
<span class="hljs-selector-class">.book-title</span>,
<span class="hljs-selector-class">.book-author</span>,
<span class="hljs-selector-class">.book-description</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-8Ss5ml2SZVM6ZLhROuRXIFeMeMVOxER164L" alt="Image" width="800" height="695" loading="lazy"></p>
<p><strong>Add/Edit Book Form</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.form</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--color-white);
}
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">'text'</span>]</span>,
<span class="hljs-selector-tag">textarea</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">10px</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">500px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--font-size-st);
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">var</span>(--color-grey);
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/pdj99DtnkIaB4-7xbtKk1AIbxBUiWt2LOSr-" alt="Image" width="800" height="695" loading="lazy"></p>
<p><strong>Actions</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.actions</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">justify-content</span>: flex-end;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--color-white);;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-built_in">var</span>(--box-shadow)
}
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KpvfySOayj7YVPKjEmFUV5uZIOTC1Z3YUTmO" alt="Image" width="800" height="45" loading="lazy"></p>
<h3 id="heading-44-the-books-route">4.4 The books route</h3>
<h4 id="heading-441-create-the-books-route"><strong>4.4.1 Create the books route</strong></h4>
<p>Now we have our styles and container DOM in place. Let’s generate a new route that will display all the books in our database:</p>
<pre><code>ember g route books
</code></pre><p>The router file <code>client/app/router.js</code> updates with:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> EmberRouter <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/routing/router'</span>;
<span class="hljs-keyword">import</span> config <span class="hljs-keyword">from</span> <span class="hljs-string">'./config/environment'</span>;
<span class="hljs-keyword">const</span> Router = EmberRouter.extend({
  <span class="hljs-attr">location</span>: config.locationType,
  <span class="hljs-attr">rootURL</span>: config.rootURL
});
Router.map(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.route(<span class="hljs-string">'books'</span>);
});
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Router;
</code></pre>
<h4 id="heading-442-load-fake-data-in-the-model-hook"><strong>4.4.2 Load fake data in the model hook</strong></h4>
<p>Let’s edit the books route <code>client/app/routes/books.js</code> to load all books from the database.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Route <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/routing/route'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Route.extend({
  model() {
    <span class="hljs-keyword">return</span> [
      {<span class="hljs-attr">title</span>: <span class="hljs-string">'Monkey Adventure'</span>},
      {<span class="hljs-attr">title</span>: <span class="hljs-string">'Island Strife'</span>},
      {<span class="hljs-attr">title</span>: <span class="hljs-string">'The Ball'</span>},
      {<span class="hljs-attr">title</span>: <span class="hljs-string">'Simple Pleasures of the South'</span>},
      {<span class="hljs-attr">title</span>: <span class="hljs-string">'Big City Monkey'</span>}
    ]
  }
});
</code></pre>
<p>The model hook is returning an array of objects. This is fake data for demonstration purposes. We’ll come back here later and load the actual data from the database using Ember Data when we’re ready.</p>
<h4 id="heading-443-update-the-books-route-template"><strong>4.4.3 Update the books route template</strong></h4>
<p>Let’s edit the books route template <code>client/app/templates/books.hbs</code>. We want to display the books returned in the model.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book-list"</span>&gt;</span>
  {{#each model as |book|}}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book"</span>&gt;</span>
      {{book.title}}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  {{/each}}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Ember uses the <a target="_blank" href="https://guides.emberjs.com/release/templates/handlebars-basics/">Handlebars Template Library</a>. Here we use the <code>each</code> helper to iterate through our array of books data in <code>model</code>. We wrap each of the items in the array in a <code>div</code> with the class <code>.book</code>. Access and display it’s title information with <code>{{book.title}}</code>.</p>
<h4 id="heading-444-demonstration-books-route-loading-and-displaying-fake-data">4.4.4 Demonstration: books route loading and displaying fake data</h4>
<p>Now that we have the DOM, <code>book</code> model, and <code>books</code> route setup with some fake data we can see this running in the browser. Take a look at <code>localhost:4200/books</code>:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Q9NHnr2xZN1Sv556vGJrBaaH-zmpHo8-qFpn" alt="Image" width="566" height="300" loading="lazy">
<em>Mouse over a book title to highlight</em></p>
<h4 id="heading-445-create-application-route-for-redirect">4.4.5 Create application route for redirect</h4>
<p>It’s kind of annoying to have to put a <code>/books</code> to visit the <code>books</code> route. Let’s generate the <code>application</code> route. We can use the <code>redirect</code> hook to redirect to the <code>books</code> route when we enter the base route <code>/</code>.</p>
<pre><code>ember g route application
</code></pre><p>If prompted to overwrite the <code>application.hbs</code> template, say no. We don’t want to overwrite the template we already set up.</p>
<p>In <code>client/app/routes/application.js</code> create the <code>redirect</code> hook:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Route <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/routing/route'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Route.extend({
  redirect() {
    <span class="hljs-built_in">this</span>.transitionTo(<span class="hljs-string">'books'</span>);
  }
});
</code></pre>
<p>Now, if you visit <code>localhost:4200</code> it will redirect to <code>localhost:4200/books</code>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Tkc46qrVylMjB6TuKWMePLOGYLaYPB7TUKc2" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-45-displaying-real-data-in-the-books-route">4.5 Displaying real data in the books route</h3>
<h4 id="heading-451-create-an-application-adapter">4.5.1 Create an application adapter</h4>
<p>We don’t want to use fake data forever. Let’s connect to the back end using an <a target="_blank" href="https://www.emberjs.com/api/ember-data/release/classes/DS.Adapter">adapter</a> and start pulling the books data into the client. Think of the adapter as an “<em>object that receives requests from a store’.</em> It <em>‘translates them into the appropriate action to take against your persistence layer…’</em></p>
<p>Generate a new application adapter:</p>
<pre><code>ember g adapter application
</code></pre><p>Locate the file <code>client/app/adapters/application.js</code> and update it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> DS <span class="hljs-keyword">from</span> <span class="hljs-string">'ember-data'</span>;
<span class="hljs-keyword">import</span> { computed } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/object'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DS.JSONAPIAdapter.extend({
  <span class="hljs-attr">host</span>: computed(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'http://localhost:8000'</span>;
  }),
  <span class="hljs-attr">namespace</span>: <span class="hljs-string">'api'</span>
});
</code></pre>
<p>The JSONAPIAdapter is the ‘<em>default adapter used by Ember Data</em>’. It transforms the store’s requests into HTTP requests that follow the <a target="_blank" href="http://jsonapi.org/format/">JSON API</a> format. It plugs into the data management library called <a target="_blank" href="https://github.com/emberjs/data">Ember Data</a>. We use Ember Data to interface with the back end in a more efficient way. It can store and manage data in the front end and make requests to the back end when required. This means minor page updates don’t need constant requests to the back end. This helps the user experience feel more fluid with generally faster loading times</p>
<p>We’ll use its <code>store</code> service to access <code>server</code> data without writing more complex <code>ajax</code> requests. These are still necessary for more complex use cases though.</p>
<p>Here the adapter is telling Ember Data that its <code>host</code> is at <code>localhost:8000</code>, namespaced to <code>api</code>. This means that any requests to the server start with <code>http://localhost:8000/api/</code>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4lhfnmvPDvGNC0229Z2VqfVVNyn4W5hd4YVs" alt="Image" width="800" height="726" loading="lazy">
<em>The full stack</em></p>
<h4 id="heading-452-create-the-book-model">4.5.2 Create the book model</h4>
<p>Ember Data has particular requirements for mapping its data to what comes from the back end. We’ll generate a <code>book</code> model so it understands what the data coming from the back end should map to:</p>
<pre><code>ember g model book
</code></pre><p>Locate the file in <code>client/models/book.js</code> and define the <code>book</code> model:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> DS <span class="hljs-keyword">from</span> <span class="hljs-string">'ember-data'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DS.Model.extend({
  <span class="hljs-attr">title</span>: DS.attr(),
  <span class="hljs-attr">author</span>: DS.attr(),
  <span class="hljs-attr">description</span>: DS.attr()
});
</code></pre>
<p>The attributes are the same as those we’ve defined in the back end. We define them again so that Ember Data knows what to expect from the structured data.</p>
<h4 id="heading-453-update-the-books-route">4.5.3 Update the <code>books</code> route</h4>
<p>Let’s update the books route by importing the <code>store</code> service and using it to request data.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Route <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/routing/route'</span>;
<span class="hljs-keyword">import</span> { inject <span class="hljs-keyword">as</span> service } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/service'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Route.extend({
  <span class="hljs-attr">store</span>: service(),
  model() {
    <span class="hljs-keyword">const</span> store = <span class="hljs-built_in">this</span>.get(<span class="hljs-string">'store'</span>);
    <span class="hljs-keyword">return</span> store.findAll(<span class="hljs-string">'book'</span>);
  }
});
</code></pre>
<h4 id="heading-454-demonstration-books-has-a-cors-issue">4.5.4 Demonstration: books has a CORS issue</h4>
<p>So far we’ve created an application adapter and updated the <code>books</code> route to query for all books in the database. Let’s see what we’re getting back.</p>
<p>Run both the Django and Ember servers. Then visit <code>localhost:4200/books</code> and you should see this in the console:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/YofsmuPXJQOamQVnPvs-0dJnGEvCl8LfWure" alt="Image" width="786" height="838" loading="lazy"></p>
<p>There seems to be a problem with CORS.</p>
<h4 id="heading-455-resolve-the-cross-origin-resource-sharing-cors-issue">4.5.5 Resolve the Cross-Origin Resource Sharing (CORS) issue</h4>
<p>CORS defines a way in which browser and server interact to determine whether it’s safe to allow a request. We’re making a cross-origin request from <code>localhost:4200</code> to <code>localhost:8000/api/books</code>. From the client to the server with the purpose of accessing our books data.</p>
<p>Currently, the front end isn’t an allowed origin to request data from our back-end endpoints. This block is causing our error. We can resolve this issue by allowing requests to pass through.</p>
<p>Begin by installing an app that adds CORS headers to responses:</p>
<pre><code>pip install django-cors-headers
</code></pre><p>Install it into <code>server</code>'s <code>settings.py</code> file under the <code>INSTALLED_APPS</code> array:</p>
<pre><code>INSTALLED_APPS = [
...
    <span class="hljs-string">'books'</span>,
    <span class="hljs-string">'corsheaders'</span>
]
</code></pre><p>Add it to the top of the <code>MIDDLEWARE</code> array:</p>
<pre><code>MIDDLEWARE = [
    <span class="hljs-string">'corsheaders.middleware.CorsMiddleware'</span>,
...
]
</code></pre><p>Finally, allow all requests to get through during development:</p>
<pre><code>CORS_ORIGIN_ALLOW_ALL = DEBUG
</code></pre><h4 id="heading-456-demonstration-cors-issue-resolved-incompatible-data-format">4.5.6 Demonstration: CORS issue resolved, incompatible data format</h4>
<p>Visit <code>localhost:4200</code> and you should see this in the console:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0klx5kEzDhADK2vxluljOK1uArhWk4PuuPF9" alt="Image" width="786" height="713" loading="lazy"></p>
<p>Looks like we solved the CORS issue and we’re receiving a response from <code>server</code> with the data that we expect:</p>
<pre><code class="lang-json">[
    {
        <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Conquistador"</span>,
        <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Buddy Levy"</span>,
        <span class="hljs-attr">"description"</span>: <span class="hljs-string">"It was a moment unique in ..."</span>
    },
    {
        <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"East of Eden"</span>,
        <span class="hljs-attr">"author"</span>: <span class="hljs-string">"John Steinbeck"</span>,
        <span class="hljs-attr">"description"</span>: <span class="hljs-string">"In his journal, Nobel Prize ..."</span>
    }
]
</code></pre>
<p>Although get an array of objects in JSON format, it’s still not in the format we want it to be. This is what Ember Data expects:</p>
<pre><code class="lang-json">{
  data: [
    {
      id: <span class="hljs-string">"1"</span>,
      type: <span class="hljs-string">"book"</span>,
      attributes: {
        title: <span class="hljs-string">"Conquistador"</span>,
        author: <span class="hljs-string">"Buddy Levy"</span>,
        description: <span class="hljs-string">"It was a moment unique in ..."</span>
      }
    },
    {
      id: <span class="hljs-string">"2"</span>,
      type: <span class="hljs-string">"book"</span>,
      attributes: {
        title: <span class="hljs-string">"East of Eden"</span>,
        author: <span class="hljs-string">"John Steinbeck"</span>,
        description: <span class="hljs-string">"In his journal, Nobel Prize ..."</span>
      }
    }
  ]
}
</code></pre>
<p>Close but not quite there yet.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/pBr8ZzZtGrBW-ubnBWvlfwv-7tEkxpIxlrV3" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-46-conclusion">4.6 Conclusion</h3>
<p>We’ve completed the following steps in <strong>Section 4</strong>:</p>
<ul>
<li>Installed NodeJS and NPM</li>
<li>Installed the Ember CLI and created a new client project</li>
<li>Basic DOM setup</li>
<li>Created a <code>books</code> route and template to load and display books</li>
<li>Demonstrated the app running with fake data</li>
<li>Created an application adapter to connect to the back end and receive data</li>
<li>Created a <code>book</code> model and updated the <code>books</code> route to capture back-end data</li>
<li>Demonstrated that the back-end data isn’t structured in the way that Ember Data expects it to be</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/zRshD6WOw8j2R4PwhMmm4eBJ650PkDGWI9lP" alt="Image" width="500" height="668" loading="lazy">
<em>This one’s mine</em></p>
<h3 id="heading-section-5-correct-data-formats-deal-with-individual-records-1">Section 5: Correct data formats, deal with individual records</h3>
<p>In this section we’ll use the Django REST Framework JSON API to structure the data in a way that Ember Data can work with. We’ll also update the <code>books</code> API to return book a single instance of a book record. We’ll also add the functionality to add, edit, and create books. Then we’re done with our application!</p>
<h3 id="heading-51-install-the-django-rest-framework-json-api">5.1 Install the Django REST Framework JSON API</h3>
<p>First we use pip to install the <a target="_blank" href="https://github.com/django-json-api/django-rest-framework-json-api">Django REST Framework JSON API</a> (DRF). It will transform regular DRF responses into an <code>identity</code> model in <a target="_blank" href="http://jsonapi.org/format/#document-resource-object-identification">JSON API format</a>.</p>
<p>With the virtual environment enabled:</p>
<pre><code># install the Django REST Framework <span class="hljs-built_in">JSON</span> API
  pip install djangorestframework-jsonapi
</code></pre><p>Next, update DRF settings in <code>server/server/settings.py</code>:</p>
<pre><code>REST_FRAMEWORK = {
  <span class="hljs-string">'PAGE_SIZE'</span>: <span class="hljs-number">100</span>,

  <span class="hljs-string">'EXCEPTION_HANDLER'</span>: 
    <span class="hljs-string">'rest_framework_json_api.exceptions.exception_handler'</span>,

  <span class="hljs-string">'DEFAULT_PAGINATION_CLASS'</span>:    <span class="hljs-string">'rest_framework_json_api.pagination.JsonApiPageNumberPagination'</span>,
<span class="hljs-string">'DEFAULT_PARSER_CLASSES'</span>: (
    <span class="hljs-string">'rest_framework_json_api.parsers.JSONParser'</span>,
    <span class="hljs-string">'rest_framework.parsers.FormParser'</span>,
    <span class="hljs-string">'rest_framework.parsers.MultiPartParser'</span>
  ),
<span class="hljs-string">'DEFAULT_RENDERER_CLASSES'</span>: (
    <span class="hljs-string">'rest_framework_json_api.renderers.JSONRenderer'</span>,
    <span class="hljs-string">'rest_framework.renderers.BrowsableAPIRenderer'</span>,
   ),
<span class="hljs-string">'DEFAULT_METADATA_CLASS'</span>: <span class="hljs-string">'rest_framework_json_api.metadata.JSONAPIMetadata'</span>,
<span class="hljs-string">'DEFAULT_FILTER_BACKENDS'</span>: (
     <span class="hljs-string">'rest_framework.filters.OrderingFilter'</span>,
    ),
<span class="hljs-string">'ORDERING_PARAM'</span>: <span class="hljs-string">'sort'</span>,

   <span class="hljs-string">'TEST_REQUEST_RENDERER_CLASSES'</span>: (
     <span class="hljs-string">'rest_framework_json_api.renderers.JSONRenderer'</span>,
    ),

   <span class="hljs-string">'TEST_REQUEST_DEFAULT_FORMAT'</span>: <span class="hljs-string">'vnd.api+json'</span>
}
</code></pre><p>These override the default settings for DRF with defaults from the JSON API. I increased the <code>PAGE_SIZE</code> so we can get up to 100 books back in a response.</p>
<h3 id="heading-52-working-with-individual-book-records">5.2 Working with individual book records</h3>
<h4 id="heading-521-create-a-view">5.2.1 Create a view</h4>
<p>Let’s also update our <code>books</code> API so that we can retrieve single instances of a book record.</p>
<p>Create a new view called<code>bookRudView</code> in <code>server/books/api/views.py</code>:</p>
<pre><code class="lang-py"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">bookRudView</span>(<span class="hljs-params">generics.RetrieveUpdateDestroyAPIView</span>):</span>
  resource_name       = <span class="hljs-string">'books'</span>
  lookup_field        = <span class="hljs-string">'id'</span>
  serializer_class    = bookSerializer
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_queryset</span>(<span class="hljs-params">self</span>):</span>
    <span class="hljs-keyword">return</span> Book.objects.all()
</code></pre>
<p>This view uses the <code>id</code> <code>lookup_field</code> to retrieve an individual book record. The <a target="_blank" href="http://www.django-rest-framework.org/api-guide/generic-views/#retrieveupdatedestroyapiview">RetrieveUpdateDestroyAPIView</a> provides basic <code>GET</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> method handlers. As you might imagine these let us create, update, and delete individual book data.</p>
<h4 id="heading-522-update-the-book-api-urls">5.2.2 Update the book API URLs</h4>
<p>We’ll need to create a new URL pattern that delivers data through the <code>bookRudView</code>.</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> .views <span class="hljs-keyword">import</span> bookAPIView, bookRudView
<span class="hljs-keyword">from</span> django.conf.urls <span class="hljs-keyword">import</span> url
urlpatterns = [
  url(<span class="hljs-string">r'^$'</span>, bookAPIView.as_view(), name=<span class="hljs-string">'book-create'</span>),
  url(<span class="hljs-string">r'^(?P&lt;id&gt;\d+)'</span>, bookRudView.as_view(), name=<span class="hljs-string">'book-rud'</span>)
]
</code></pre>
<p>Import <code>bookRudView</code>, match it to the pattern <code>r'^(?P&lt;id&gt;</code>;\d+)', and give it the name <code>book-rud</code>.</p>
<h4 id="heading-523-update-the-server-urls">5.2.3 Update the server URLs</h4>
<p>Finally, update the <code>books</code> API URL pattern in <code>server/server/urls.py</code>. We want to match to patterns which begin after <code>books/</code>:</p>
<pre><code>...
urlpatterns = [
  ...
  url(r<span class="hljs-string">'^api/books/?'</span>, include(<span class="hljs-string">'books.api.urls'</span>, namespace=<span class="hljs-string">'api-books'</span>)),
]
</code></pre><h4 id="heading-524-demonstration-access-a-single-book-record">5.2.4 Demonstration: Access a single book record</h4>
<p>Now if you visit <code>localhost:8000/api/books/1</code> it should display a single book record that matches to a book’s <code>id</code>:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/CUK0sNAqhaAp-aYXHTN0o-gCCToOtM4gUg3z" alt="Image" width="800" height="812" loading="lazy"></p>
<p>Notice that we have access to the <code>DELETE</code>, <code>PUT</code>, <code>PATCH</code> and other methods. These come with <code>RetrieveUpdateDestroyAPIView</code>.</p>
<h4 id="heading-525-demonstration-capturing-and-displaying-data-from-the-back-end-in-the-correct-format">5.2.5 Demonstration: Capturing and displaying data from the back end in the correct format</h4>
<p>With the <code>JSONAPI</code> installed the back end should be sending back responses Ember can work with. Run both servers and visit <code>localhost:4200/books</code>. We should get back real data from the back end and have the route display it. Success!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/9RQ7BOzrDZuruIw65IraJFmkz9DlN0WJ0bw5" alt="Image" width="800" height="234" loading="lazy">
<em>Capturing and displaying data from the back end</em></p>
<p>Take a look at the response coming through. It’s in the valid <code>JSONAPI</code> format that Ember Data works with.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Hz-SsH8c5UYq6InAy1jeCxwgNlHnMQ4AJ58L" alt="Image" width="760" height="595" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/PIGhJY1TrhBHlHDRfzeKcev5qvR1XX9aP62C" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-53-the-book-route">5.3 The book Route</h3>
<p>We can now view the list of books from our database in the <code>books</code> route. Next, let’s create a new route in the front-end <code>client</code>. It will display individual books in detail with <code>title</code>, <code>author</code>, and <code>description</code> data.</p>
<h4 id="heading-531-create-the-book-route">5.3.1 Create the <code>book</code> route</h4>
<p>Generate a new route for the individual book page:</p>
<pre><code>ember g route book
</code></pre><p>In <code>router.js</code> update the new route with the path <code>‘books/:book_id’</code>. This overrides the default path and takes in a <code>book_id</code> parameter.</p>
<pre><code>...
Router.map(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.route(<span class="hljs-string">'books'</span>);
  <span class="hljs-built_in">this</span>.route(<span class="hljs-string">'book'</span>, { <span class="hljs-attr">path</span>: <span class="hljs-string">'books/:book_id'</span> });
});
...
</code></pre><p>Next update the <code>book</code> route <code>client/app/routes/book.js</code> to retrieve a single book record from the database:</p>
<pre><code><span class="hljs-keyword">import</span> Route <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/routing/route'</span>;
<span class="hljs-keyword">import</span> { inject <span class="hljs-keyword">as</span> service } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/service'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Route.extend({
  <span class="hljs-attr">store</span>: service(),
model(book) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.get(<span class="hljs-string">'store'</span>).peekRecord(<span class="hljs-string">'book'</span>, book.book_id);
  }
});
</code></pre><p>As outlined in <code>router.js</code> the <code>book</code> route takes in the <code>book_id</code> parameter. The parameter goes into the route’s <code>model</code> hook and we use it to retrieve the book with the Ember Data <code>store</code>.</p>
<h4 id="heading-532-update-the-book-template">5.3.2 Update the <code>book</code> template</h4>
<p>Our <code>client/app/templates/book.hbs</code> template should display the book data we get back from the <code>store</code>. Get rid of <code>{{outlet}}</code> and update it:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book book--detail"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book-title"</span>&gt;</span>
    {{model.title}}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book-author"</span>&gt;</span>
    {{model.author}}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book-description"</span>&gt;</span>
    {{model.description}}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Like in the <code>books</code> template we access the <code>model</code> attributes using <a target="_blank" href="https://codeburst.io/javascript-quickie-dot-notation-vs-bracket-notation-333641c0f781">dot notation</a>.</p>
<h4 id="heading-533-update-the-books-template">5.3.3 Update the <code>books</code> template</h4>
<p>Finally, let’s update the <code>books</code> template. We want to link to each individual book page as displayed in the <code>book</code> route we created:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"book-list"</span>&gt;</span>
  {{#each model as |book|}}
    {{#link-to 'book' book.id class="book"}}
      {{book.title}}
    {{/link-to}}
  {{/each}}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Wrap the <code>book.title</code> with the <code>link-to</code> helper. It works like this:</p>
<ul>
<li>creates a link to the <code>book</code> route</li>
<li>takes in the <code>book.id</code> as a parameter</li>
<li>takes a <code>class</code> to style the <code>&lt;</code>;a&gt; tag generated in the DOM.</li>
</ul>
<h4 id="heading-534-demonstration-select-book-to-view-detailed-information">5.3.4 Demonstration: Select book to view detailed information</h4>
<p>Now check out <code>localhost:4200/books</code>. We can click on our books to get a detailed view. Sweet!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hyC6r85lGgPWSydWXWcCppI10y0v0yo4-1sC" alt="Image" width="800" height="476" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/kfuloJ1VtO6CV09r3CsY-2Gcl9Dd3ts8kt3G" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-54-conclusion">5.4 Conclusion</h3>
<p>We’ve come to the end of <strong>Section 5</strong> with the following steps completed:</p>
<ul>
<li>Identified the problem with the data coming from Django</li>
<li>Installed the Django REST Framework JSON API</li>
<li>Updated the <code>books</code> route template</li>
<li>Created the <code>book</code> route and template</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MLAvJIJz8ChUSLcFJi4DFuVyMVcnlnzoMU87" alt="Image" width="500" height="372" loading="lazy">
<em>Getting into the details now</em></p>
<h3 id="heading-section-6-functional-front-end-1">Section 6: Functional Front end</h3>
<p>In this section we’ll add the following functionality to the front-end experience:</p>
<ul>
<li>Add a new book with the fields title, author, and description</li>
<li>Edit an existing book’s title, author, and description fields</li>
<li>Delete an existing book</li>
</ul>
<p>That’s all we have to do to complete the rest of our application. We come a long way. Let’s push on to the end!</p>
<h3 id="heading-61-adding-a-new-book-to-the-database">6.1 Adding a new book to the database</h3>
<p>We can now view all the books from the database and view individual book records in detail. It’s time to build the functionality to add a new book to the database. These are the steps we’ll take to make that happen:</p>
<ul>
<li>The <code>create-book</code> route handles the process of creating a new book and adding it to the database</li>
<li>The <code>create-book</code> template will have a form with two inputs and a text area to take in a <code>title</code>, <code>author</code>, and <code>description</code></li>
<li>The <code>create-book</code> controller handles the data entered into the form</li>
</ul>
<h4 id="heading-611-create-the-create-book-route-and-controller">6.1.1 Create the create-book route and controller</h4>
<p>Generate the <code>create-book</code> route to handle new book creation:</p>
<pre><code>ember g route create-book
</code></pre><p>Create a controller of the same name to hold form data:</p>
<pre><code>ember g controller create-book
</code></pre><h4 id="heading-612-setup-the-create-book-controller">6.1.2 Setup the <code>create-book</code> controller</h4>
<p>In <code>client/app/controllers/create-book.js</code> create a computed property called <code>form</code>. It will return an object with our book data attributes. This is where we capture the new book data entered in by the user. It’s empty by default.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Controller <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/controller'</span>;
<span class="hljs-keyword">import</span> { computed } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/object'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Controller.extend({
  <span class="hljs-attr">form</span>: computed(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
      <span class="hljs-attr">author</span>: <span class="hljs-string">''</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">''</span>
    }
  })
});
</code></pre>
<h4 id="heading-613-setup-the-create-book-route">6.1.3 Setup the <code>create-book</code> route</h4>
<p>In <code>client/app/routes/create-book.js</code> we do the following:</p>
<ul>
<li>create actions to confirm creation of a new book</li>
<li>cancel the creation process</li>
<li>use a route hook to clear the form data upon entering the route:</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Route <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/routing/route'</span>;
<span class="hljs-keyword">import</span> { inject <span class="hljs-keyword">as</span> service } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/service'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Route.extend({
  <span class="hljs-attr">store</span>: service(),
  setupController(controller, model) {
    <span class="hljs-built_in">this</span>._super(controller, model);
    <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'form.title'</span>, <span class="hljs-string">''</span>);
    <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'form.author'</span>, <span class="hljs-string">''</span>);
    <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'form.description'</span>, <span class="hljs-string">''</span>);
  },
  <span class="hljs-attr">actions</span>: {
    create() {
      <span class="hljs-keyword">const</span> form = <span class="hljs-built_in">this</span>.controller.get(<span class="hljs-string">'form'</span>);
      <span class="hljs-keyword">const</span> store = <span class="hljs-built_in">this</span>.get(<span class="hljs-string">'store'</span>);
      <span class="hljs-keyword">const</span> newBook = store.createRecord(<span class="hljs-string">'book'</span>, {
        <span class="hljs-attr">title</span>: form.title,
        <span class="hljs-attr">author</span>: form.author,
        <span class="hljs-attr">description</span>: form.description
      });
      newBook.save()
        .then(<span class="hljs-function">() =&gt;</span> {
          <span class="hljs-built_in">this</span>.transitionTo(<span class="hljs-string">'books'</span>);
        });
     },
     cancel() {
       <span class="hljs-built_in">this</span>.transitionTo(<span class="hljs-string">'books'</span>);
     }
  }
});
</code></pre>
<p>The <code>setupController</code> hook allows us to reset the form’s values. This is so that they don’t persist when we go back and forth through pages. We don’t want to click away to another page without having completed the create book process. If we do, we’ll come back to see the unused data still sitting in our form.</p>
<p>The <code>create()</code> action will take the form data and create a new record with the Ember Data <code>store</code>. It then persists it to the Django back end. Once complete it will transition the user back to the <code>books</code> route.</p>
<p>The <code>cancel</code> button transitions the user back to the <code>books</code> route.</p>
<h4 id="heading-614-setup-the-create-book-template">6.1.4 Setup the <code>create-book</code> template</h4>
<p>Next, in <code>client/app/template/create-book.hbs</code> we build the form:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
    Add a new book
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  {{input
    value=form.title
    name="title"
    placeholder="Title"
    autocomplete='off'
  }}
  {{input
    value=form.author
    name="author"
    placeholder="Author"
    autocomplete='off'
  }}
  {{textarea
    value=form.description
    name="description"
    placeholder="Description"
    rows=10
  }}
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"actions"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> '<span class="hljs-attr">create</span>'}}&gt;</span>
      Create
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> '<span class="hljs-attr">cancel</span>'}}&gt;</span>
      Cancel
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The <code>form</code> uses the built-in <code>{{input}}</code> helpers to:</p>
<ul>
<li>take in values</li>
<li>display placeholders</li>
<li>turn autocomplete off.</li>
</ul>
<p>The <code>{{text}}</code> area helper works in a similar way, with the addition of the number of rows.</p>
<p>The actions <code>div</code> contains the two buttons to create and cancel. Each button ties to its namesake action using the <code>{{action}}</code> helper.</p>
<h4 id="heading-615-update-the-books-route-template">6.1.5 Update the <code>books</code> route template</h4>
<p>The final piece of the create book puzzle is to add a button in the <code>books</code> route. It will get us into the <code>create-book</code> route and begin creating a new book.</p>
<p>Add on to the bottom of <code>client/app/templates/books.hbs</code>:</p>
<pre><code>...
{{#link-to <span class="hljs-string">'create-book'</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">'btn btn-addBook'</span>}}
  Add Book
{{/link-to}}
</code></pre><h4 id="heading-616-demonstration-can-add-a-new-book">6.1.6 Demonstration: Can add a new book</h4>
<p>Now if we go back and try to create a new book again we’ll find success. Click into the book to see a more detailed view:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/8ktkFGXqUnl-f3OtzVczYW5Oa4JlfrhEv7Ev" alt="Image" width="800" height="718" loading="lazy">
<em>Adding a new book to the library</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7JlRVM4oznuSb0K7FKRdCInNKKVeGOFcy0VS" alt="Image" width="800" height="718" loading="lazy">
<em>New book created and displayed</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/BUdQmE0HUaMn9xhRvWXR7GI0jU-NlXu8SmzW" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-62-deleting-a-book-from-the-database">6.2 Deleting a book from the database</h3>
<p>Now that we can add books to the database we should be able to delete them too.</p>
<h4 id="heading-621-update-the-book-route-template">6.2.1 Update the <code>book</code> route template</h4>
<p>First update the <code>book</code> route’s template. Add on under <code>book book--detail</code>:</p>
<pre><code class="lang-html">...
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"actions {{if confirmingDelete
                         'u-justify-space-between'}}"</span>&gt;</span>
  {{#if confirmingDelete}}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-text-danger"</span>&gt;</span>
      Are you sure you want to delete this book?
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> '<span class="hljs-attr">delete</span>' <span class="hljs-attr">model</span>}}&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> (<span class="hljs-attr">mut</span> <span class="hljs-attr">confirmingDelete</span>)<span class="hljs-attr">false</span>}}&gt;</span>
        Cancel
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  {{else}}
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> (<span class="hljs-attr">mut</span> <span class="hljs-attr">confirmingDelete</span>) <span class="hljs-attr">true</span>}}&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  {{/if}}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The <code>actions</code> <code>div</code> contains the buttons and text for the book deletion process.</p>
<p>We have a <code>bool</code> called <code>confirmingDelete</code> which will be set on the route’s <code>controller</code>. <code>confirmingDelete</code> adds the <code>.u-justify-space-between</code> utility class on <code>actions</code> when it’s <code>true</code>.</p>
<p>When it’s true, it also displays a prompt with the utility class <code>.u-text-danger</code>. This prompts the user to confirm deletion of the book. Two buttons show up. One to run <code>delete</code> action in our route. The other uses the <code>mut</code> helper to flip <code>confirmingDelete</code> to <code>false</code>.</p>
<p>When <code>confirmingDelete</code> is <code>false</code> (the default state) a single <code>delete</code> button display. Clicking it flips <code>confirmingDelete</code> to <code>true</code>. This then displays the prompt and the other two buttons.</p>
<h4 id="heading-622-update-the-book-route">6.2.2 Update the <code>book</code> route</h4>
<p>Next update the <code>book</code> route. Under the <code>model</code> hook add:</p>
<pre><code>setupController(controller, model) {
  <span class="hljs-built_in">this</span>._super(controller, model);
  <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'confirmingDelete'</span>, <span class="hljs-literal">false</span>);
},
</code></pre><p>In <code>setupController</code> we call <code>this._super()</code>. This is so the controller goes through its usual motions before we do our business. Then we set <code>confirmingDelete</code> to <code>false</code>.</p>
<p>Why do we do this? Let’s say we start to delete a book, but leave the page without either cancelling the action or deleting the book. When we go to any book page <code>confirmingDelete</code> would be set to <code>true</code> as a leftover.</p>
<p>Next let’s create an <code>actions</code> object that will hold our route actions:</p>
<pre><code>actions: {
  <span class="hljs-keyword">delete</span>(book) {
    book.deleteRecord();
    book.save().then(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">this</span>.transitionTo(<span class="hljs-string">'books'</span>);
    });
  }
}
</code></pre><p>The <code>delete</code> action as referenced in our template takes in a <code>book</code>. We run <code>deleteRecord</code> on the <code>book</code> and then <code>save</code> to persist the change. Once that promise completes <code>transitionTo</code> transitions to the <code>books</code> route (our list view).</p>
<h4 id="heading-623-demonstration-can-delete-an-existing-book">6.2.3 Demonstration: Can delete an existing book</h4>
<p>Let’s check this out in action. Run the servers and select a book you want to delete.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/X3g8JcJt5Gh7OfgE4G3JPvszzlEE902n8BJK" alt="Image" width="800" height="705" loading="lazy">
<em>Delete button visible when confirmingDelete is false</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/VsfnqMVBFAce2azSvhDa1kIkBKYSzZ68RhIk" alt="Image" width="800" height="649" loading="lazy">
<em>Prompt to confirm deletion of book when confirmingDelete is true</em></p>
<p>When you delete the book it redirects to the <code>books</code> route.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/9OqjwQPyAxDXv9JCgoYGYpF8ARv6WZd-DK4h" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-63-editing-a-book-in-the-database">6.3 Editing a book in the database</h3>
<p>Last but not least we’ll add the functionality to edit an existing books information.</p>
<h4 id="heading-631-update-the-book-route-template">6.3.1 Update the <code>book</code> route template</h4>
<p>Open up the <code>book</code> template and add a form to update book data:</p>
<pre><code class="lang-html">{{#if isEditing}}
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>Edit<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {{input
      value=form.title
      placeholder="Title"
      autocomplete='off'
    }}
    {{input
      value=form.author
      placeholder="Author"
      autocomplete='off'
    }}
    {{textarea
      value=form.description
      placeholder="Description"
      rows=10
    }}
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"actions"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> '<span class="hljs-attr">update</span>' <span class="hljs-attr">model</span>}}&gt;</span>Update<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> (<span class="hljs-attr">mut</span> <span class="hljs-attr">isEditing</span>) <span class="hljs-attr">false</span>}}&gt;</span>Cancel<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{{else}}
  ...
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> (<span class="hljs-attr">mut</span> <span class="hljs-attr">isEditing</span>) <span class="hljs-attr">true</span>}}&gt;</span>Edit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> {{<span class="hljs-attr">action</span> (<span class="hljs-attr">mut</span> <span class="hljs-attr">confirmingDelete</span>) <span class="hljs-attr">true</span>}}&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  ...
{{/if}}
</code></pre>
<p>First let’s wrap the entire template in an <code>if</code> statement. This corresponds to the <code>isEditing</code> property which by default will be <code>false</code>.</p>
<p>Notice that the form is very almost identical to our create book form. The only real difference is that the actions <code>update</code> runs the <code>update</code> action in the <code>book</code> route. The <code>cancel</code> button also flips the <code>isEditing</code> property to <code>false</code>.</p>
<p>Everything we had before gets nested inside the <code>else</code>. We add the <code>Edit</code> button to flip <code>isEditing</code> to true and display the form.</p>
<h4 id="heading-632-create-a-book-controller-to-handle-form-values">6.3.2 Create a <code>book</code> controller to handle form values</h4>
<p>Remember the <code>create-book</code> controller? We used it to hold the values that’s later sent to the server to create a new book record.</p>
<p>We’ll use a similar method to get and display the book data in our <code>isEditing</code> form. It will pre-populate the form with the current book’s data.</p>
<p>Generate a book controller:</p>
<pre><code>ember g controller book
</code></pre><p>Open <code>client/app/controllers/book.js</code> and create a <code>form</code> computed property like before. Unlike before we’ll use the <code>model</code> to pre-populate our form with the current <code>book</code> data:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Controller <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/controller'</span>;
<span class="hljs-keyword">import</span> { computed } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ember/object'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Controller.extend({
  <span class="hljs-attr">form</span>: computed(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> model = <span class="hljs-built_in">this</span>.get(<span class="hljs-string">'model'</span>);
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">title</span>: model.get(<span class="hljs-string">'title'</span>),
      <span class="hljs-attr">author</span>: model.get(<span class="hljs-string">'author'</span>),
      <span class="hljs-attr">description</span>: model.get(<span class="hljs-string">'description'</span>)
    }
  })
});
</code></pre>
<h4 id="heading-633-update-the-book-route">6.3.3 Update the <code>book</code> route</h4>
<p>We’ll have to update our route again:</p>
<pre><code class="lang-js">setupController(controller, model) {
  ...
  this.controller.set(<span class="hljs-string">'isEditing'</span>, <span class="hljs-literal">false</span>);
  <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'form.title'</span>, model.get(<span class="hljs-string">'title'</span>));
  <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'form.author'</span>, model.get(<span class="hljs-string">'author'</span>));
  <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'form.description'</span>, model.get(<span class="hljs-string">'description'</span>));
},
</code></pre>
<p>Let’s add on to the <code>setupController</code> hook. Set <code>isEditing</code> to <code>false</code> and reset all the form values to their defaults.</p>
<p>Next let’s create the <code>update</code> action:</p>
<pre><code class="lang-js">actions: {
  ...
  update(book) {
    <span class="hljs-keyword">const</span> form = <span class="hljs-built_in">this</span>.controller.get(<span class="hljs-string">'form'</span>);
    book.set(<span class="hljs-string">'title'</span>, form.title);
    book.set(<span class="hljs-string">'author'</span>, form.author);
    book.set(<span class="hljs-string">'description'</span>, form.description);
    book.save().then(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">this</span>.controller.set(<span class="hljs-string">'isEditing'</span>, <span class="hljs-literal">false</span>);
    });
  }
}
</code></pre>
<p>It’s pretty straightforward. We get the form values, set those values on the <code>book</code> and persist with <code>save</code>. Once successful we flip <code>isEditing</code> back to <code>false</code>.</p>
<h4 id="heading-634-demonstration-can-edit-information-of-an-existing-book">6.3.4 Demonstration: Can edit information of an existing book</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/xMgtmxnN122AZPurNoIFRX3QyQ6WVR909YOc" alt="Image" width="800" height="667" loading="lazy">
<em>Edit button to toggle the isEditing controller property</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/XBlE7hYhZIyRzAhbtDVBPMUFy3ZNJseyVU6p" alt="Image" width="800" height="614" loading="lazy">
<em>Form pre-populated with book’s current information</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/r5A-y2Xi4sDOwQrza0ClHizr5VNmXbloXM58" alt="Image" width="800" height="614" loading="lazy">
<em>Book updated with new information</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jHXRFAZRrJLz3vqbqdsmxPCYsYVOrxu2qogA" alt="Image" width="800" height="80" loading="lazy"></p>
<h3 id="heading-64-conclusion">6.4 Conclusion</h3>
<p>We’ve completed the following steps by the end of <strong>Section 6</strong>:</p>
<ul>
<li>Identified the problem with the data coming from Django</li>
<li>Installed JSON API into Django</li>
<li>Updated the Books Route Template</li>
<li>Created the book detail route and template</li>
<li>Can view, add, edit, and delete database records from the EmberJS client</li>
</ul>
<p><strong>That’s it. We’ve done it! We built a very basic full stack application using Django and Ember.</strong></p>
<p>Let’s step back and think about what we’ve built for a minute. We have an application called <code>my_library</code> that:</p>
<ul>
<li>lists books from a database</li>
<li>allows users to view each book in more detail</li>
<li>add a new book</li>
<li>edit an existing book</li>
<li>delete a book</li>
</ul>
<p>As we built the application we learned about Django and how it’s used to administer the database. We created models, serializers, views, and URL patterns to work with the data. We used Ember to create a user interface to access and change the data through the API endpoints.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KTyH3U0QWUOf8LUEIgKEXovuO8gabreUhKHN" alt="Image" width="500" height="290" loading="lazy">
<em>Phew</em></p>
<h3 id="heading-section-7-moving-on-1">Section 7: Moving On</h3>
<h3 id="heading-71-whats-next">7.1 What’s Next</h3>
<p>If you’ve gotten this far, you’ve finished the tutorial! The application is running with all the intended functionality. That’s a lot to be proud of. Software development, complicated? That’s an understatement. It can feel downright inaccessible even with all the resources available to us. I get that feeling all the time.</p>
<p>What works for me is to take frequent breaks. Get up and walk away from what you’re doing. Do something else. Then get back and break down your problems step by step into the smallest units. Fix and refactor until you get to where you want to be. There are no shortcuts to building your knowledge.</p>
<p>Anyways, we’ve might have done a lot here for an introduction but we’re only scratching the surface. There is plenty more for you to learn about full stack development. Here are some examples to think about:</p>
<ul>
<li>user accounts with authentication</li>
<li>testing functionality of the application</li>
<li>deploying the application to the web</li>
<li>writing the REST API from scratch</li>
</ul>
<p>When I have time I’ll look into writing more on these topics myself.</p>
<p>I hope you found this tutorial useful. It’s intended to serve as a jump-off point for you to learn more about Django, Ember and full stack development. It was definitely a learning experience for me. <strong>Shoutout to my <a target="_blank" href="http://closingfolders.com/">Closing Folders</a> team for the support and encouragement. We’re hiring now so feel free to get in touch!</strong></p>
<p>If you’d like to reach out you can contact me through the following channels:</p>
<ul>
<li><a target="_blank" href="mailto:michael.xavier@closingfolders.com">email</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/vinothmichaelxavier/">linkedIn</a></li>
<li><a target="_blank" href="https://medium.com/@sunskyearthwind">medium</a></li>
<li><a target="_blank" href="https://lookininward.github.io/">personal website</a></li>
</ul>
<h3 id="heading-72-further-reading">7.2 Further Reading</h3>
<p>Writing this tutorial forced me confront the edges of my knowledge. Here are the resources that helped with my comprehension of the topics covered:</p>
<p><a target="_blank" href="http://qr.ae/TUIx4x">What is a full stack programmer?</a><br><a target="_blank" href="https://stackoverflow.com/a/8694944/5513243">What is a web application?</a><br><a target="_blank" href="https://tutorial.djangogirls.org/en/django/">What is Django?</a><br><a target="_blank" href="https://hacks.mozilla.org/2014/02/ember-js-what-it-is-and-why-we-need-to-care-about-it/">What is EmberJS?</a><br><a target="_blank" href="https://www.atlassian.com/git/tutorials/what-is-version-control">What is version control?</a><br><a target="_blank" href="https://medium.com/swlh/git-as-the-newbies-learning-steroid-963a2146220b">What is Git?</a><br><a target="_blank" href="http://rogerdudler.github.io/git-guide/">How do I use Git with Github?</a><br><a target="_blank" href="https://help.github.com/articles/create-a-repo/">How do I create a Git repository?</a><br><a target="_blank" href="https://help.github.com/articles/adding-a-remote/">How do I add a Git remote?</a><br><a target="_blank" href="https://docs.djangoproject.com/en/1.11/topics/db/models/">What is a model?</a><br><a target="_blank" href="https://docs.djangoproject.com/en/1.11/topics/http/views/">What is a view?</a><br><a target="_blank" href="https://docs.djangoproject.com/en/1.11/ref/django-admin/#createsuperuser">What is a superuser?</a><br><a target="_blank" href="https://docs.djangoproject.com/en/2.1/ref/django-admin/#django-admin-makemigrations">What is making a migration?</a><br><a target="_blank" href="https://docs.djangoproject.com/en/2.1/ref/django-admin/#django-admin-migrate">What is migrating?</a><br><a target="_blank" href="https://www.sqlite.org/about.html">What is SQLite?</a><br><a target="_blank" href="https://www.makeuseof.com/tag/json-python-parsing-simple-guide/">JSON Python Parsing: A Simple Guide</a><br><a target="_blank" href="https://medium.freecodecamp.org/how-to-securely-store-api-keys-4ff3ea19ebda">How to secure API keys</a><br><a target="_blank" href="https://www.python.org/doc/essays/blurb/">What is Python?</a><br><a target="_blank" href="https://en.wikipedia.org/wiki/Pip_(package_manager)">What is pip?</a><br><a target="_blank" href="https://virtualenv.pypa.io/en/stable/">What is virtualenv?</a><br><a target="_blank" href="http://libzx.so/main/learning/2016/03/13/best-practice-for-virtualenv-and-git-repos.html">Best practices for virtualenv and git repo</a><br><a target="_blank" href="https://medium.freecodecamp.org/what-is-an-api-in-english-please-b880a3214a82">What is an API?</a><br><a target="_blank" href="https://smartbear.com/learn/performance-monitoring/api-endpoints/">What are API endpoints?</a><br><a target="_blank" href="http://www.django-rest-framework.org/">What is the Django REST Framework?</a><br><a target="_blank" href="https://stackoverflow.com/a/448279/5513243">What is <strong>init</strong>.py?</a><br><a target="_blank" href="http://www.django-rest-framework.org/api-guide/serializers/">What is a serializer?</a><br><a target="_blank" href="https://docs.djangoproject.com/en/1.11/topics/http/views/">What are views?</a><br><a target="_blank" href="https://tutorial.djangogirls.org/en/django_urls/">What are URLS?</a><br><a target="_blank" href="https://www.w3schools.com/js/js_json_intro.asp">What is JSON?</a><br><a target="_blank" href="https://www.tutorialspoint.com/python/python_reg_expressions.htm">What are regular expressions?</a><br><a target="_blank" href="https://stackoverflow.com/questions/448271/what-is-init-py-for/448279#448279">What does <strong>init</strong>.py do?</a><br><a target="_blank" href="http://rest.elkstein.org/">What is REST?</a><br><a target="_blank" href="https://www.w3schools.com/nodejs/nodejs_intro.asp">What is Node.js?</a><br><a target="_blank" href="https://www.w3schools.com/nodejs/nodejs_npm.asp">What is NPM?</a><br><a target="_blank" href="https://hacks.mozilla.org/2014/02/ember-js-what-it-is-and-why-we-need-to-care-about-it/">What is EmberJS?</a><br><a target="_blank" href="https://ember-cli.com/">What is Ember CLI?</a><br><a target="_blank" href="https://github.com/emberjs/data">What is Ember-Data?</a><br><a target="_blank" href="https://guides.emberjs.com/release/models/">What is a model?</a><br><a target="_blank" href="https://guides.emberjs.com/release/routing/">What is a route?</a><br><a target="_blank" href="https://guides.emberjs.com/release/routing/defining-your-routes/">What is a router?</a><br><a target="_blank" href="https://guides.emberjs.com/release/templates/handlebars-basics/">What is a template?</a><br><a target="_blank" href="https://www.emberjs.com/api/ember-data/release/classes/DS.Adapter">What is an adapter?</a><br><a target="_blank" href="https://github.com/django-json-api/django-rest-framework-json-api">What is the Django REST Framework JSON API?</a><br><a target="_blank" href="http://jsonapi.org/format/#document-resource-object-identification">What is the JSON API format?</a><br><a target="_blank" href="https://codeburst.io/javascript-quickie-dot-notation-vs-bracket-notation-333641c0f781">What is dot notation?</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to set up a Basic Ember.js app ]]>
                </title>
                <description>
                    <![CDATA[ By Tracy Lee | ladyleet So, you want to test out Ember, eh? This article will walk through building a basic app. Here’s what we’ll do: Set up ember-cli Create a new application Use materalize-css for styling Create components Cover basic use of Embe... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/setting-up-a-basic-ember-js-app-c9323760c675/</link>
                <guid isPermaLink="false">66c35ea5e9895571912a0d17</guid>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ember ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 09 Aug 2016 13:06:53 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*--wRIhx_atl50C4NlkMY5Q.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Tracy Lee | ladyleet</p>
<p>So, you want to test out Ember, eh? This article will walk through building a basic app.</p>
<p>Here’s what we’ll do:</p>
<ol>
<li>Set up ember-cli</li>
<li>Create a new application</li>
<li>Use materalize-css for styling</li>
<li>Create components</li>
<li>Cover basic use of Ember’s router</li>
<li>Explore the “each” helper for iterating over data</li>
</ol>
<p>First things first, you should install ember-cli. Almost all applications are built with ember-cli. It’s very rare that you’ll find one that is not.</p>
<p>And here’s one major benefit of Ember and the Ember community — they rely on convention over configuration more heavily than Angular and React do. They use this as one of their strengths, making them a popular framework for companies who want to build large scale applications.</p>
<p>Being conventional allows Ember to develop community standards such as the ember-cli-deploy story, a strong story around Ember Data, and the loads of contributions the community is able to make through the ember addon ecosystem. (check out <a target="_blank" href="http://emberaddons.com">emberaddons.com</a>)</p>
<p>At the Ember.js website, you’ll find simple install instructions, and even a little quick start guide you can walk through!</p>
<p>Go ahead and install ember-cli to get started:</p>
<pre><code>$ npm install -g ember-cli
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/uqa1TXkxiRmvCzpk7hKIiniHqBLG6iIlOidM" alt="Image" width="800" height="476" loading="lazy"></p>
<h3 id="heading-creating-a-new-application">Creating a new application</h3>
<p>This is as easy as 1–2–3! Simply _ember new  and an application will be generated for you.</p>
<pre><code>ember <span class="hljs-keyword">new</span> yolobrolo
</code></pre><p>You’ll see ember-cli creating quite a few files.</p>
<p>Mainly, you should note that Ember has created:</p>
<ul>
<li>application.hbs (handlebars, which is your html file)</li>
<li>app.js</li>
<li>router.js</li>
<li>package.json</li>
<li>bower.json</li>
<li>tests</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/u8W1gwGP09Zm9SswoeMYnPcym2cZePWx39XO" alt="Image" width="620" height="1170" loading="lazy"></p>
<p>Wahoo! Now, if you open up your IDE, you should see the structure of an Ember application.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/rSeUbwBASJqaUUNzMoTrTs28kxJhjAZk9tG7" alt="Image" width="800" height="890" loading="lazy"></p>
<h3 id="heading-installing-materialize-css">Installing Materialize-CSS</h3>
<p>In case you were wondering, I love material design and materialize-css.</p>
<p>So, if you want to use the styles I usually use, go ahead run the following command.</p>
<pre><code>npm install materialize-css
</code></pre><p>Then, add these lines to your index.html file</p>
<pre><code>&lt;!-- Compiled and minified CSS --&gt;  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css"</span>&gt;</span></span>
</code></pre><pre><code>&lt;!--Import Google Icon Font--&gt;      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"http://fonts.googleapis.com/icon?family=Material+Icons"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span></span>
</code></pre><pre><code>&lt;!-- Compiled and minified JavaScript --&gt;  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre><p>When done, kill your server and restart it. Your font should change to Roboto:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/QKBS1fALwjuOdlEBzEprrNZ0Hpea5l9fzMUL" alt="Image" width="506" height="196" loading="lazy">
<em>Before you install materialize-css</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZeV8v2aKw-6kJDbt0f4rqBcOp8MI-HfdsrCt" alt="Image" width="716" height="270" loading="lazy">
<em>After you install materialize-css</em></p>
<h3 id="heading-creating-components">Creating components</h3>
<p>Ember, like most JavaScript frameworks these days, loves components. So let’s create the component we need: a navigation bar that we can hook up the router to! We use the nav bar that materialize-css gives us.</p>
<p>All you need to do to create a component is this:</p>
<pre><code>ember g component &lt;component-name&gt;
</code></pre><p>Make sure the name of your component has a dash in the name as this is the convention.</p>
<p>Here are the files that ember-cli generates for me. It creates:</p>
<ul>
<li>component-name.hbs</li>
<li>component-name.js</li>
<li>adds integration tests</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/tVx23HTngPpZy6FbsA5sVClrDttak5F0hCDl" alt="Image" width="800" height="282" loading="lazy"></p>
<p>This is what my pretty nav-bar looks like.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ucWBKTzvkOz9s0-EDNfg4yKLYCa5gfyZej9a" alt="Image" width="800" height="50" loading="lazy"></p>
<p>Here’s the default code if you like:</p>
<pre><code>&lt;nav&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-wrapper"</span>&gt;</span>      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"brand-logo center"</span>&gt;</span>Logo<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"nav-mobile"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"left hide-on-med-and-down"</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Videos<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>  &lt;/nav&gt;
</code></pre><p>Anytime you need to reuse a piece of code over and over again, it’s always best to make it a component. :)</p>
<h3 id="heading-using-embers-router">Using Ember’s router</h3>
<p>I think I take Ember’s router for granted after playing around in Angular 2 so much.</p>
<p>Actually, I think I take routers for granted in general, but here is my friend <a target="_blank" href="http://twitter.com/_jayphelps">Jay Phelps</a> telling us why we should care.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Fehcpksz1hYRDLluNfc9KIiEkYV6AZRxe6Co" alt="Image" width="676" height="107" loading="lazy"></p>
<p>Here’s a basic overview of how Ember’s router works.</p>
<p>First things first, you should note there is a router.js file in which all of your routes are defined. Also, in your application.hbs file, there is {{outlet}} which outputs whatever you specify the router to.</p>
<p>In my app, I want to create 2 simple routes — an about page and a videos page.</p>
<p>To create a new route you run this command in ember-cli.</p>
<pre><code>ember g route &lt;route-name&gt;
</code></pre><p>Ember will then generate:</p>
<ul>
<li>your-route.js</li>
<li>your-route.hbs</li>
<li>update the router.js file</li>
<li>create a unit test.</li>
</ul>
<p>You can see all the magic from the command line:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/9znjBZrRbIzyM904Ipvuz-n4No7cVK5Vzx7M" alt="Image" width="800" height="327" loading="lazy"></p>
<p>I love how the router.js file is automatically updated for me. You can even create nested routes from the command line. The Ember.js guides are pretty awesome and here is a <a target="_blank" href="https://guides.emberjs.com/v2.7.0/routing/">link</a> to everything the router can do.</p>
<p>One thing I did in the screenshot below was define my default route. I did that by simply specifying the route path as /. Everything else was pre-generated for me with the CLI.</p>
<pre><code><span class="hljs-built_in">this</span>.route(‘videos’, { <span class="hljs-attr">path</span>:’/’ });
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/Hunm2wpFTJLIrxai0zNs5fDobyVih1T3qnN-" alt="Image" width="800" height="610" loading="lazy"></p>
<h3 id="heading-configuring-the-output-of-embers-router">Configuring the output of Ember’s router</h3>
<p>Let’s explore the application.hbs file. This is where the router will output.</p>
<p>Really, one of the only things I add into my application.hbs file is a navigation bar and footer. I create routes for everything else.</p>
<p>Currently my application.hbs file looks like this.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/tpeGX5M4bI9DMzh1CoIbMZgC6HB371LwsB3r" alt="Image" width="566" height="226" loading="lazy"></p>
<p>Now, going into my nav-bar component I’m going to get routes going for the about page route and the videos route.</p>
<p>Ember uses the {{link-to}} helper for transitions between routes.</p>
<p>Here’s what the syntax looks like:</p>
<pre><code>{{#link-to ‘videos’}}Videos{{/link-to}}
</code></pre><p>The {{link-to}} helper replaces an <a> tag and is the way we transition between routes in Ember. All you need to do is specify the route in the parens as shown above. In Angular 2, the equivalent is the routerLink.</a></p>
<p>Here’s a screenshot of my entire nav-bar.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2tLmQelJpI7fPu4zx7kVk1h1c3hbxNFTFmkG" alt="Image" width="800" height="335" loading="lazy"></p>
<p>Now you know how to use the very basic functionality of the router!</p>
<h3 id="heading-iterating-over-data-using-the-each-helper">Iterating Over Data Using the Each Helper</h3>
<p>I have a video route, and I’d like to display a set of YouTube videos on the page. I’m going to create a simple video-card component that I will be iterating over and displaying on the video page.</p>
<p>This is what one video card looks like:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2zrsP51jykbjvWpM8p5MORF7zHch9vKUab8E" alt="Image" width="482" height="394" loading="lazy"></p>
<p>Part of Ember’s beauty is all the helpers that allow you to do cool things in your app.</p>
<p>Ember’s {{each}} helper is equivalent to the ng-repeat directive in Angular 1 and the *ngFor directive in Angular 2.</p>
<p>Full ember docs on the each helper and helpers in general are <a target="_blank" href="https://guides.emberjs.com/v2.6.0/templates/displaying-a-list-of-items/">here</a>.</p>
<p>Here is what the code for one YouTube video displayed looks like:</p>
<pre><code>&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=”row”&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”col</span> <span class="hljs-attr">s12</span> <span class="hljs-attr">m6</span> <span class="hljs-attr">l4</span>"&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”card-panel</span> <span class="hljs-attr">center-align</span>”&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”purple-text”</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”video-container”</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">iframe</span> <span class="hljs-attr">width</span>=<span class="hljs-string">”853</span>" <span class="hljs-attr">height</span>=<span class="hljs-string">”480</span>" <span class="hljs-attr">src</span>=<span class="hljs-string">”https://www.youtube.com/embed/peNV2yJRMLo?rel</span>=<span class="hljs-string">0</span>" <span class="hljs-attr">frameborder</span>=<span class="hljs-string">”0</span>" <span class="hljs-attr">allowfullscreen</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">iframe</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”purple-text”</span>&gt;</span> With Taras Mankovski <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>&lt;/div&gt;
</code></pre><p>After laying it out, I realize that I want to iterate over 3 pieces of data — the title, the YouTube video link, and the person featured in the video.</p>
<p>So, I need to define my data in an array in my component.js file like such:</p>
<pre><code>model: [{ <span class="hljs-attr">title</span>: “Ember DND Helper”, <span class="hljs-attr">people</span>: “Taras Mankovski”, <span class="hljs-attr">videoLink</span>: “peNV2yJRMLo?rel=<span class="hljs-number">0</span>” },{ <span class="hljs-attr">title</span>: “Dependency Injection <span class="hljs-keyword">in</span> Angular <span class="hljs-number">2</span>”, <span class="hljs-attr">people</span>: “Patrick J. Stapleton”, <span class="hljs-attr">videoLink</span>: “<span class="hljs-number">46</span>WovCX8i-I?rel=<span class="hljs-number">0</span>” },{ <span class="hljs-attr">title</span>: “Angular CLI”, <span class="hljs-attr">people</span>: “Mike Brocchi”, <span class="hljs-attr">videoLink</span>: “BmZLpNRNnZo” },{ <span class="hljs-attr">title</span>: “Angular Material <span class="hljs-number">2</span> Spelunking &amp; Issue Submission”, <span class="hljs-attr">people</span>: “Ben Lesh”, <span class="hljs-attr">videoLink</span>: “<span class="hljs-number">3</span>gNsyL7wpXU” }]});
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/7cZ-psmEqKoJFd8Bhwa5GJQ3JvgkoIoDChyk" alt="Image" width="800" height="581" loading="lazy"></p>
<p>Then, I can finally use the {{each}} helper to iterate over my data.</p>
<p>Wrap the content with the {{each}} helper as below, defining the model and your local variable:</p>
<pre><code>{{#each model <span class="hljs-keyword">as</span> |video|}} CONTENT {{/each}}
</code></pre><p>Then, take the pieces of content you’d like to be dynamic and replace it with handlebars and localVariable.x, like so:</p>
<pre><code>{{video.title}}
</code></pre><pre><code>src=<span class="hljs-string">"https://www.youtube.com/embed/{{video.videoLink}}"</span>
</code></pre><pre><code>{{video.people}}
</code></pre><p>Here’s what the code looks like when it’s all said and done:</p>
<pre><code>&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=”row”&gt; {{#each model <span class="hljs-keyword">as</span> |video|}} &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=”col s12 m6 l4<span class="hljs-string">"&gt; &lt;div class=”card-panel center-align”&gt; &lt;div class=”purple-text”&gt; &lt;p&gt;{{video.title}}&lt;/p&gt; &lt;/div&gt; &lt;div class=”video-container”&gt; &lt;iframe width=”853"</span> height=”<span class="hljs-number">480</span><span class="hljs-string">" src=”https://www.youtube.com/embed/{{video.videoLink}}"</span> frameborder=”<span class="hljs-number">0</span><span class="hljs-string">" allowfullscreen&gt;&lt;/iframe&gt; &lt;/div&gt; &lt;div class=”purple-text”&gt; With {{video.people}} &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; {{/each}}&lt;/div&gt;</span>
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/T2HQ0WWJGoeyNxuq3Mpxd1B5kvl6mYb2fLQl" alt="Image" width="800" height="256" loading="lazy"></p>
<p>Here’s the end result of using the {{each}} helper.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/rVFQkwb9b69ARcyfSUzwkGDpYFg02inh5kgA" alt="Image" width="800" height="576" loading="lazy"></p>
<h3 id="heading-deploying-to-heroku"><strong>Deploying to Heroku</strong></h3>
<p>Once upon a time there existed a man called tonycoco. And tonycoco made deploying ember apps to Heroku super easy. Here’s his <a target="_blank" href="https://github.com/tonycoco/heroku-buildpack-ember-cli">github repo</a> if you want to peep in on this.</p>
<p>First, you should have the Heroku Toolbelt installed and linked with your Heroku account.</p>
<p>Then, all you have to do to deploy to Heroku is commit your changes to master and push.</p>
<pre><code>$ heroku create — buildpack https:<span class="hljs-comment">//github.com/tonycoco/heroku-buildpack-ember-cli.git</span>
</code></pre><pre><code>$ git push heroku master
</code></pre><p>Wait for it to finish deploying completely.</p>
<p>Go into your <a target="_blank" href="https://dashboard.heroku.com/apps">Heroku app dashboard</a>. Update app to the name you want (to match your app).</p>
<p>Now change the Heroku remote name to match new app name in your .git/config file.</p>
<p>Then, <em>git push heroku master</em> again and you should be all set!</p>
<p>In this case, this app deployed: <a target="_blank" href="http://yolobrolo-ember-1.herokuapp.com/">http://yolobrolo-ember-1.herokuapp.com/</a></p>
<p>Yolo! Have fun with it. Hope you try out Ember and enjoy it.</p>
<h3 id="heading-watch-me-build-this-step-by-step"><strong>Watch me build this step by step</strong></h3>
<p>Oh also, for your viewing purposes, you can watch me build this <a target="_blank" href="https://www.youtube.com/watch?v=-Ury2S9Y-4Q">on YouTube at yolobrolo</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
