<?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" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Zach Garwood]]></title><description><![CDATA[Software Developer]]></description><link>https://zachgarwood.blog/</link><image><url>https://zachgarwood.blog/favicon.png</url><title>Zach Garwood</title><link>https://zachgarwood.blog/</link></image><generator>Ghost 3.22</generator><lastBuildDate>Wed, 18 Feb 2026 20:51:51 GMT</lastBuildDate><atom:link href="https://zachgarwood.blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Joy Jar]]></title><description><![CDATA[<p>I just released a small web app called <a href="https://joyjar.zachgarwood.com/">Joy Jar</a>. I made it for storing away precious memories and pulling them back out when you need to think happy thoughts. The idea is that when something makes you smile – an inside joke! a bit of nostalgia! a hopeful wish! – take</p>]]></description><link>https://zachgarwood.blog/joy-jar/</link><guid isPermaLink="false">5eff7bba9d8d900ee7f84cf1</guid><category><![CDATA[Projects]]></category><category><![CDATA[Django]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Fri, 03 Jul 2020 22:57:26 GMT</pubDate><content:encoded><![CDATA[<p>I just released a small web app called <a href="https://joyjar.zachgarwood.com/">Joy Jar</a>. I made it for storing away precious memories and pulling them back out when you need to think happy thoughts. The idea is that when something makes you smile – an inside joke! a bit of nostalgia! a hopeful wish! – take a moment to jot it down in the the app. Then whenever you need a pick-me-up, open the app and pull a few random joys from your jar.</p><p>Making this toy app was a fun little project. Building something that promotes positive thinking during this chaotic age gave me the motivation to actually finish it – which is something that can't be said for the majority of the side projects I start. I'd attempted to build something similar to this app a couple times over the years, but always got distracted halfway thru. Spending all Spring indoors, hiding from the pandemic, gave me ample free time to focus on getting it done this time.</p><p>This project is <a href="https://gitlab.com/zachgarwood/joy_jar">written in Python using the Django framework</a>. Python is and has been my favorite programming language since I learned it, and even tho Django is a pretty heavy-duty framework for such a small project, I chose it for educational reasons. Despite having worked with three large Django codebases over the course my career, it feels like there's so much more to learn. So I'm also going to use this project as an opportunity to install new libraries, explore unfamiliar techniques, and dig into the Django internals.</p>]]></content:encoded></item><item><title><![CDATA[The Graide Network Is on Fire]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>My long-time client, <a href="http://www.thegraidenetwork.com/">The Graide Network</a>, recently won <a href="http://chicagoinno.streetwise.co/all-series/announcing-the-chicago-inno-2016-50-on-fire-winners/">ChicagoInno's 50 on Fire</a>! It feels nice to be a part of such an innovative team.</p>
<!--kg-card-end: markdown-->]]></description><link>https://zachgarwood.blog/the-graide-network-is-on-fire/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3ea</guid><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Fri, 09 Dec 2016 21:44:42 GMT</pubDate><media:content url="https://zachgarwood.blog/content/images/2019/06/50-on-fire.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://zachgarwood.blog/content/images/2019/06/50-on-fire.png" alt="The Graide Network Is on Fire"><p>My long-time client, <a href="http://www.thegraidenetwork.com/">The Graide Network</a>, recently won <a href="http://chicagoinno.streetwise.co/all-series/announcing-the-chicago-inno-2016-50-on-fire-winners/">ChicagoInno's 50 on Fire</a>! It feels nice to be a part of such an innovative team.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Chicago, Where's My Car?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>August 24, 2019: This website is no longer maintained.</em></p>
<p>I created <a href="https://chicago-wheres-my-car.web.app/">Chicago, Where's My Car?</a> to make it easy to find out if your vehicle has been towed or relocated by the City of Chicago, and to where. It utilizes <a href="https://emberobserver.com/addons/ember-socrata"><code>ember-socrata</code></a>, the Ember addon <a href="https://zachgarwood.blog/ember-socrata/">I recently created</a>, to consume data</p>]]></description><link>https://zachgarwood.blog/chicago-wheres-my-car/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e9</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Fri, 08 Jul 2016 20:23:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><em>August 24, 2019: This website is no longer maintained.</em></p>
<p>I created <a href="https://chicago-wheres-my-car.web.app/">Chicago, Where's My Car?</a> to make it easy to find out if your vehicle has been towed or relocated by the City of Chicago, and to where. It utilizes <a href="https://emberobserver.com/addons/ember-socrata"><code>ember-socrata</code></a>, the Ember addon <a href="https://zachgarwood.blog/ember-socrata/">I recently created</a>, to consume data provided by <a href="https://data.cityofchicago.org/">the City of Chicago's open data portal</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Ember-Socrata]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I recently created an Ember addon for consuming <a href="https://socrata.com/">Socrata</a> open data resources: <a href="https://emberobserver.com/addons/ember-socrata"><code>ember-socrata</code></a>. Subsequently, someone over at Socrata found my library and asked me to write a bit on how to use it, so I created a <a href="https://dev.socrata.com/blog/2016/06/30/quickly-building-an-ember-app-backed-by-socrata-open-data.html">quick follow-along tutorial</a> and <a href="https://cta-ridership.firebaseapp.com/">live example</a>.</p>
<!--kg-card-end: markdown-->]]></description><link>https://zachgarwood.blog/ember-socrata/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e8</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Fri, 01 Jul 2016 20:08:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I recently created an Ember addon for consuming <a href="https://socrata.com/">Socrata</a> open data resources: <a href="https://emberobserver.com/addons/ember-socrata"><code>ember-socrata</code></a>. Subsequently, someone over at Socrata found my library and asked me to write a bit on how to use it, so I created a <a href="https://dev.socrata.com/blog/2016/06/30/quickly-building-an-ember-app-backed-by-socrata-open-data.html">quick follow-along tutorial</a> and <a href="https://cta-ridership.firebaseapp.com/">live example</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Ember-Syncano]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I was recently hired by a company called Syncano to write their official Ember CLI addon: <a href="https://github.com/Syncano/ember-syncano">Ember-Syncano</a>. I'd never written an Ember CLI addon before, so it was a learning experience for me. I feel like I should write more about my experience, but I think I may contemplate my</p>]]></description><link>https://zachgarwood.blog/ember-syncano/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e7</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Wed, 30 Mar 2016 21:25:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I was recently hired by a company called Syncano to write their official Ember CLI addon: <a href="https://github.com/Syncano/ember-syncano">Ember-Syncano</a>. I'd never written an Ember CLI addon before, so it was a learning experience for me. I feel like I should write more about my experience, but I think I may contemplate my experience a bit more and possibly write a tutorial on the process.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Professional, Published Author]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I wrote an article for the Code School blog: <a href="https://zachgarwood.blog/dynamic-sorting-in-ember-js/">Dynamic Sorting in Ember.js</a> to coincide with the recent launch of their new Ember courses.</p>
<p>My twenty-two-year-old self would be proud! His dream of getting paid to be a freelance tech journalist is finally realized ... ten years later. It feels</p>]]></description><link>https://zachgarwood.blog/professional-published-author/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e6</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Tutorials]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Mon, 21 Mar 2016 19:37:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I wrote an article for the Code School blog: <a href="https://zachgarwood.blog/dynamic-sorting-in-ember-js/">Dynamic Sorting in Ember.js</a> to coincide with the recent launch of their new Ember courses.</p>
<p>My twenty-two-year-old self would be proud! His dream of getting paid to be a freelance tech journalist is finally realized ... ten years later. It feels sort of surreal but pretty rewarding to earn a paycheck for writing a tutorial that I probably would have written anyway and published here for free.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Dynamic Sorting in Ember.js]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>January 7, 2019: This article was originally published on the now-defunct CodeSchool.com blog. See the <a href="https://web.archive.org/web/20160818215956/https://www.codeschool.com/blog/2016/03/21/dynamic-sorting-in-emberjs">Internet Archive snapshot</a>.</em></p>
<p>Most modern web applications that display lists or tables of data often offer the user some mechanism for sorting that data dynamically. From the developer’s point of view, this would</p>]]></description><link>https://zachgarwood.blog/dynamic-sorting-in-ember-js/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3eb</guid><category><![CDATA[Ember]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Mon, 21 Mar 2016 17:44:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><em>January 7, 2019: This article was originally published on the now-defunct CodeSchool.com blog. See the <a href="https://web.archive.org/web/20160818215956/https://www.codeschool.com/blog/2016/03/21/dynamic-sorting-in-emberjs">Internet Archive snapshot</a>.</em></p>
<p>Most modern web applications that display lists or tables of data often offer the user some mechanism for sorting that data dynamically. From the developer’s point of view, this would ideally happen client-side without the need to contact the server and requerying for the resorted data. So today I want to explore how this can be accomplished in an Ember app.</p>
<p>In this blog post, I’ll be assuming you’re using <a href="http://ember-cli.com/">Ember CLI</a> &gt;= 2.3.0. If you’d like to follow along with the tutorial, I’ve created a base project you can check out <a href="https://github.com/zachgarwood/ember-sorting-demo">here</a>, or you can view the completed tutorial code <a href="https://github.com/zachgarwood/ember-sorting-demo/tree/completed-tutorial">here</a>.</p>
<h2 id="thescenario">The Scenario</h2>
<p>Let’s imagine we’re working on a product review site. We’ve been given the task of creating a component to display the reviews for a given product and allow for them to be sorted by date, rating, or the name of the reviewer.</p>
<p>We open up the Review model and it looks like this:</p>
<pre><code class="language-javascript">// app/models/review.js

import DS from 'ember-data';

export default DS.Model.extend({
  date: DS.attr('date'),
  product: DS.belongsTo('product'),
  rating: DS.attr('number'), // score out of 5
  text: DS.attr('string'),
  title: DS.attr('string'),
  username: DS.attr('string'),
});
</code></pre>
<p>We see that each review contains a reference to a product, a title, some text, a rating, as well as the date it was written and the username of the user who wrote it. Let’s get started!</p>
<h2 id="thebasics">The Basics</h2>
<p>First, let’s generate the component scaffolding:</p>
<pre><code class="language-bash">ember generate component review-list
</code></pre>
<p>Now, since our component will be a list of reviews, let’s update our component’s tag to use the list tag <code>&lt;ul&gt;</code>.</p>
<pre><code class="language-javascript">// app/components/review-list.js

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'ul',
});
</code></pre>
<p>Next, we’ll create a basic template to output the reviews as we received them — no sorting just yet.</p>
<pre><code class="language-javascript">{{!-- app/templates/components/review-list.hbs --}}

{{#each reviews as |review|}}
  &lt;li&gt;
    &lt;h3&gt;{{review.title}} - {{review.rating}} out of 5&lt;/h3&gt;
    &lt;p&gt;{{review.text}}&lt;/p&gt;
    &lt;p&gt;by {{review.username}} on {{review.date}}&lt;/p&gt;
  &lt;/li&gt;
{{/each}}
</code></pre>
<p>Each review is contained inside a list element. It displays a title and the rating out of five, the full text of the review, and a byline. Right now, it’s just pretty simple stuff.</p>
<p>Now, let’s add our component to the Product template:</p>
<pre><code class="language-javascript">{{!-- app/templates/product.hbs --}}

&lt;h1&gt;{{model.title}}&lt;/h1&gt;

&lt;img src=&quot;{{model.image}}&quot; /&gt;

&lt;hr /&gt;
&lt;h2&gt;Reviews:&lt;/h2&gt;
{{review-list reviews=model.reviews}}
</code></pre>
<p>If we run:</p>
<pre><code class="language-bash">ember serve
</code></pre>
<p>then navigate to <a href="http://localhost:4200">http://localhost:4200</a>, we should see a product with a list of reviews in no particular order. Of course that doesn’t make very much sense, so let’s sort the list.</p>
<h2 id="sorting">Sorting</h2>
<p>First, let’s sort the reviews by date:</p>
<pre><code class="language-javascript">// app/components/review-list.js

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'ul',
  sortedReviews: Ember.computed.sort('reviews', 'sortDefinition'),
  sortDefinition: ['date'],
});
</code></pre>
<p><code>Ember.computed.sort</code> takes a reference to the collection it will sort as its first argument — in this case, reviews — and a reference to a sort definition as its second. A sort definition is simply a list of properties to sort by. Each property may be followed by <code>:asc</code> or <code>:desc</code> to specify sorting in ascending or descending order. If left off, the property is sorted in ascending order by default, but more on this later. For our purposes, we’re only ever going to sort by one property at a time. And to begin with, we’ll set our <code>sortDefinition</code> to just one property, date. And that’s it — <code>Ember.computed.sort</code> handles the sorting for us! The collection of reviews returned by <code>sortedReviews</code> is now sorted by date. Now we just need to update our template to use the new <code>sortedReviews</code> property instead of <code>reviews</code>:</p>
<pre><code class="language-javascript">{{!-- app/templates/components/review-list.hbs --}}

{{!-- ... --}}
{{#each sortedReviews as |review|}}
{{!-- ... --}}
</code></pre>
<h3 id="sidenoteonthehistoryofsorting">Side Note on the History of Sorting</h3>
<p>Previously in Ember 1.x, dynamic sorting was accomplished using <code>SortableMixin</code>. A good amount of material out there still discusses using this mixin for sorting collections. However, in Ember 2, <code>SortableMixin</code> has been removed — though, inexplicably it does not appear in the <a href="http://emberjs.com/deprecations/v2.x/">2.x deprecations list</a> — in favor of <a href="http://emberjs.com/api/classes/Ember.computed.html#method_sort"><code>Ember.computed.sort</code></a>. It’s still <em>possible</em> to use <code>SortableMixin</code> in Ember 2.x via the <a href="https://github.com/emberjs/ember-legacy-controllers">ember-legacy-controllers</a> addon, but in this article we’ll be using the Ember-2.x-preferred <code>Ember.computed.sort</code>.</p>
<h3 id="choosingwhichpropertytosortby">Choosing Which Property to Sort By</h3>
<p>So, we’ve changed the reviews to be sorted by their date property. But we want to give the user the ability to choose what property to sort on — by either date, rating, or the reviewer’s username.</p>
<p>We’ll add some logic to our component to handle this:</p>
<pre><code class="language-javascript">// app/components/review-list.js

// ...
sortedReviews: Ember.computed.sort('reviews', 'sortDefinition'),
sortBy: 'date', // default sort by date
sortDefinition: Ember.computed('sortBy', function() {
  return [ this.get('sortBy') ];
}),
// ...
</code></pre>
<p>First, we create a new property in our component called <code>sortBy</code> and, in keeping consistent with the previous iteration, we’ll set the default value to <code>'date'</code>. Then we update our <code>sortDefinition</code> to be a computed property — not a sorted computed property, just your run-of-the-mill <a href="http://emberjs.com/api/classes/Ember.computed.html"><code>Ember.computed</code></a> property. We give it the name of the component property, <code>sortBy</code>, to observe for changes and a callback to return the <code>sortBy</code> property in an array. By default, <code>sortDefinition</code> will return the same value as it did before — <code>['date']</code>. But now we can change the <code>sortBy</code> value to dynamically update the property the collection of reviews is sorted by.</p>
<p>Let’s give the user the ability to update the value of <code>sortBy</code>. I think this is a perfect job for a set of radio buttons — one each for sorting by date, rating, and username. Ember doesn’t come with a built-in radio button input helper, but some fellow Emberists have already created a <a href="http://emberobserver.com/addons/ember-radio-button">nice addon</a> for us. Let’s install it so we can use it in our template:</p>
<pre><code class="language-bash">ember install ember-radio-button
</code></pre>
<pre><code class="language-javascript">{{!-- app/templates/components/review-list.hbs --}}

&lt;div&gt;
  Sort by
  {{radio-button value='date' groupValue=sortBy}} Date
  {{radio-button value='rating' groupValue=sortBy}} Rating
  {{radio-button value='username' groupValue=sortBy}} User
&lt;/div&gt;
{{!-- ... --}}
</code></pre>
<p>Here, we create a set of radio buttons, each with one of the Review properties we want to sort by as its <code>value</code>. When a radio button element is clicked, the <code>radio-button</code> helper sets the <code>groupValue</code> equal to the element’s <code>value</code>. So for instance, clicking on the <em>Rating</em> radio button will set the <code>sortBy</code> property to <code>'rating'</code>. You should see that the <em>Date</em> radio button is selected by default, and that clicking on the others changes the sorting of the reviews. Now there’s just one more thing to do — allow the user to reverse the sort order.</p>
<h3 id="choosingasortorder">Choosing a Sort Order</h3>
<p>I mentioned before that a sort definition can contain a <code>:asc</code> or <code>:desc</code> flag to denote whether the sort should be done in standard ascending order or the reverse, descending order. Let’s give the user the ability to choose this sort order.</p>
<pre><code class="language-javascript">// app/components/review-list.js

// ...
sortedReviews: Ember.computed.sort('reviews', 'sortDefinition'),
sortBy: 'date', // default sort by date
reverseSort: false, // default sort in ascending order
sortDefinition: Ember.computed('sortBy', 'reverseSort', function() {
  let sortOrder = this.get('reverseSort') ? 'desc' : 'asc';
  return [ `${this.get('sortBy')}:${sortOrder}` ];
}),
// ...
</code></pre>
<p>We add a new static property named <code>reverseSort</code> and give it a value of false so that by default, the items are sorted in ascending order. Then we update our <code>sortDefinition</code> computed property to also observe <code>reverseSort</code>. In the callback, we set the <code>sortOrder</code> flag to either <code>'desc'</code> if <code>reverseSort</code> is true or <code>'asc'</code> if it is false, then tack that flag onto the <code>sortBy</code> string, separated by a colon. If you were to log the <code>sortDefinition</code> to the console with default values of <code>sortBy</code> and <code>reverseSort</code>, it would return <code>['date:asc']</code>.</p>
<p>Now let’s update our template to put the sort ordering choice in the hands of our users.</p>
<pre><code class="language-javascript">{{!-- app/templates/components/review-list.hbs --}}

{{!-- ... --}}
&lt;div&gt;
  {{input type='checkbox' checked=reverseSort}} Reverse sort
&lt;/div&gt;
{{!-- ... --}}
</code></pre>
<p>By default, the <em>Reverse</em> sort checkbox will be unchecked, but when the user checks it, the order of the items will be reversed.</p>
<p>You should now be able to manipulate not only the property the reviews are sorted by, but also whether or not they are shown in ascending or descending order!</p>
<h3 id="evenmoresorting">Even More Sorting</h3>
<p>As I hinted at before, <code>Ember.computed.sort</code> can handle a multivariate sort definition that contains multiple properties by which to sort, each in either ascending or descending order. So even if you have some very specific sorting needs, <code>Ember.computed.sort</code> should be able to handle them.</p>
<p>That said, don’t try to reinvent the wheel. The great thing about the Ember community is that there are so many awesome addons out there. For instance, if you’re looking to sort, filter, and search a data table based on multiple criteria, give the <a href="http://emberobserver.com/addons/ember-models-table">ember-models-table</a> addon a try. In general, EmberObserver.com is a great place to find just about any kind of Ember addon you can imagine. <s>Have your own favorite addons? Let me know in the comments section below!</s></p>
<p><s>If you would like an Ember refresher, Code School’s Ember.js course, Try Ember, is a great place to start.</s></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[California Crystal]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><a href="http://california-crystal.com/">California Crystal</a> is a simple WordPress brochure site utilizing a purchased, prepackaged theme. Unfortunately, the theme turned out not to that well designed (but it was really cheap, so I guess that's to be expected), so I had to make some heavy modifications to it to make it work. All</p>]]></description><link>https://zachgarwood.blog/california-crystal/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e5</guid><category><![CDATA[Wordpress]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Thu, 10 Mar 2016 23:11:27 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><a href="http://california-crystal.com/">California Crystal</a> is a simple WordPress brochure site utilizing a purchased, prepackaged theme. Unfortunately, the theme turned out not to that well designed (but it was really cheap, so I guess that's to be expected), so I had to make some heavy modifications to it to make it work. All in all, the customer was really satisfied with the site.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Contributing to the Elixir Language]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I guess you could say that I'm an <a href="https://github.com/elixir-lang/elixir/pull/4361#event-579052016">Elixir core contributor now</a>, no big deal.</p>
<p>Elixir came back onto my radar recently because someone made a <a href="https://github.com/zachgarwood/elixir-amazon-product-advertising-client/pull/2">pull request</a> to a library that I had written and promptly abandoned over a year ago. Even just working through the simple fix for</p>]]></description><link>https://zachgarwood.blog/contributing-to-the-elixir-language/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e4</guid><category><![CDATA[Elixir]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Mon, 07 Mar 2016 02:06:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I guess you could say that I'm an <a href="https://github.com/elixir-lang/elixir/pull/4361#event-579052016">Elixir core contributor now</a>, no big deal.</p>
<p>Elixir came back onto my radar recently because someone made a <a href="https://github.com/zachgarwood/elixir-amazon-product-advertising-client/pull/2">pull request</a> to a library that I had written and promptly abandoned over a year ago. Even just working through the simple fix for my library and contributing that minor correction for the URI module in the standard library that I mentioned above has reinvigorated my interest in the language. I had forgotten how simultaneously foreign but comfortable Elixir is for me. I find it <em>exciting</em> to write in, which I can hardly say of the other languages I'm familiar with. I need to hurry up and finish the other side projects I'm juggling at the moment so I can find some idea worth implementing in Elixir.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[List Maker]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><a href="https://brilliant-inferno-3512.firebaseapp.com/">List Maker</a> is a fun side project written in <a href="http://emberjs.com/">Ember</a>. It utilizes the <a href="https://www.firebase.com/docs/web/libraries/ember/">EmberFire</a> and <a href="https://vestorly.github.io/torii/">Torii</a> addons to authenticate (so far, only using Facebook) and store data via the <a href="https://www.firebase.com">Firebase</a> service.</p>
<p>Anonymous users can browse and read lists. Authenticated uses can start new lists and add items to any list.</p>]]></description><link>https://zachgarwood.blog/list-maker/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e3</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Fri, 29 Jan 2016 01:24:07 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><a href="https://brilliant-inferno-3512.firebaseapp.com/">List Maker</a> is a fun side project written in <a href="http://emberjs.com/">Ember</a>. It utilizes the <a href="https://www.firebase.com/docs/web/libraries/ember/">EmberFire</a> and <a href="https://vestorly.github.io/torii/">Torii</a> addons to authenticate (so far, only using Facebook) and store data via the <a href="https://www.firebase.com">Firebase</a> service.</p>
<p>Anonymous users can browse and read lists. Authenticated uses can start new lists and add items to any list. List items consist of a title and an optional description and image. Users are only allowed to edit and delete lists and items that they have contributed.</p>
<p>Rough patches:</p>
<ul>
<li>Input validation</li>
<li>Error handling</li>
<li>Error feedback</li>
<li>UI in general</li>
</ul>
<p>Features still to come:</p>
<ul>
<li>User's view of their contributed lists and list items</li>
<li>User voting/liking for lists and items</li>
<li>List and item ranking</li>
<li>More authentication platform options</li>
<li>Social media sharing options</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Ember Firebase Demo]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I created this <a href="https://ember-firebase-demo.firebaseapp.com/">follow-along demo</a> for my <a href="https://zachgarwood.blog/2016/01/25/user-authentication-made-easy-with-firebase/">User Authentication Made Easy with Firebase</a> tutorial. It's written in <a href="http://emberjs.com/">Ember</a> and uses the <a href="https://www.firebase.com/docs/web/libraries/ember/">EmberFire</a> and <a href="https://vestorly.github.io/torii/">Torii</a> addons for authenticating via the <a href="https://www.firebase.com/">Firebase</a> service. It also makes use of the <a href="https://kaliber5.github.io/ember-bootstrap/">Bootstrap</a> and <a href="https://github.com/martndemus/ember-cli-font-awesome">Font Awesome</a> addons to make it more visually appealing.</p>
<p>The app</p>]]></description><link>https://zachgarwood.blog/ember-firebase-demo/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e2</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Thu, 28 Jan 2016 22:02:31 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I created this <a href="https://ember-firebase-demo.firebaseapp.com/">follow-along demo</a> for my <a href="https://zachgarwood.blog/2016/01/25/user-authentication-made-easy-with-firebase/">User Authentication Made Easy with Firebase</a> tutorial. It's written in <a href="http://emberjs.com/">Ember</a> and uses the <a href="https://www.firebase.com/docs/web/libraries/ember/">EmberFire</a> and <a href="https://vestorly.github.io/torii/">Torii</a> addons for authenticating via the <a href="https://www.firebase.com/">Firebase</a> service. It also makes use of the <a href="https://kaliber5.github.io/ember-bootstrap/">Bootstrap</a> and <a href="https://github.com/martndemus/ember-cli-font-awesome">Font Awesome</a> addons to make it more visually appealing.</p>
<p>The app allows the user to sign up, sign in, and sign out. When they are authenticated, users can see the Welcome page that displays their user information. The app demonstrates action-based redirection (eg. When the user signs in, they are taken the the Welcome page) and authentication-based redirections (eg. If the user is not authenticated, they are redirected from the Welcome page to the Home page). The app specifically lacks input validation and proper error handling, as those items were out of the scope of the tutorial and left up to the reader to implement.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[User Authentication Made Easy with Firebase]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>Note: This tutorial is for version 2.x of the Firebase SDK and some of its content may be outdated.</em></p>
<p>No matter what sort of application you're creating, you almost always have to allow your app's users to sign in and out. Including user authentication functionality in a project is</p>]]></description><link>https://zachgarwood.blog/user-authentication-made-easy-with-firebase/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e1</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Tutorials]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Mon, 25 Jan 2016 23:24:34 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><em>Note: This tutorial is for version 2.x of the Firebase SDK and some of its content may be outdated.</em></p>
<p>No matter what sort of application you're creating, you almost always have to allow your app's users to sign in and out. Including user authentication functionality in a project is time-consuming, often wrought with gotchas, and just plain boring. It's necessary to make your app function, but it takes time away from getting to the nitty gritty of what your app is actually designed to do.</p>
<p>I've been messing around a bit with Firebase recently. It's an interesting &quot;cloud&quot;-based noSQL data store. But the feature that really caught my eye about it is its user authentication capabilities. The authentication feature is billed as an ancillary side benefit to the main data storage functionality, but I think that Firebase makes it so simple to do user authentication for client-side web applications, that I'd even recommend using it for just that feature alone! I'd like to show you just how easy it is to make an authenticated web application using the Ember framework and Firebase.</p>
<aside>Firebase has support for many different frameworks and languages, client-side and server-side; I just really enjoy using Ember at the moment.</aside>
<h2 id="whatyouneedtobegin">What You Need to Begin</h2>
<p>In this article, I will assume you have <a href="http://ember-cli.com/">Ember CLI</a> installed. I will also assume you have at least a basic familiarity with <a href="http://emberjs.com/">Ember</a>. I'll go into detail about the code we're writing as we go, but I won't be doing an exhaustive, line-by-line break-down. The Ember documentation is pretty good, though, and can fill in any gaps I might leave. You can see a live demo of the code <a href="https://ember-firebase-demo.firebaseapp.com/">here</a>. All the code for this demo is located at <a href="https://github.com/zachgarwood/ember-firebase-demo">https://github.com/zachgarwood/ember-firebase-demo</a>.</p>
<p>So, let's get started!</p>
<h2 id="setupandconfiguration">Setup and Configuration</h2>
<h3 id="ember">Ember</h3>
<p>Create a new Ember project and jump into the project directory:</p>
<pre><code class="language-bash">ember new ember-firebase-demo
cd ember-firebase-demo/
</code></pre>
<h3 id="firebase">Firebase</h3>
<p>To set up Firebase to handle user authentication, go to <a href="https://firebase.com">https://firebase.com</a>, sign up for a free account, and create an app. Go to your app's management screen by clicking the <em>Manage App</em> button. In the sidebar menu, select the <em>Login &amp; Auth</em> tab, then check the <em>Enable Email &amp; Password Authentication</em> box.<br>
<img src="https://zachgarwood.blog/content/images/2016/01/enable-email-and-password-authentication.png" alt="Enable Email &amp; Password Authentication"></p>
<p>To set up our project to use Firebase, go back to your terminal and install the EmberFire addon:</p>
<pre><code class="language-bash">ember install emberfire
</code></pre>
<p>When it's done installing, you should have a new <code>app/adapters/application.js</code> file and a new <code>firebase</code> property on the <code>ENV</code> object in the application's config file (<code>config/environment.js</code>). Replace &quot;YOUR-FIREBASE-NAME&quot; with whatever you named your Firebase app (in this example, &quot;ember-firebase-demo&quot;):</p>
<pre><code class="language-javascript">//config/environment.js

module.exports = function(environment) {
  var ENV = {
//...
    environment: environment,
    contentSecurityPolicy: { 'connect-src': &quot;'self' https://auth.firebase.com wss://*.firebaseio.com&quot; },
    firebase: 'https://ember-firebase-demo.firebaseio.com/',
    baseUrl: '/',
//...
  }
}
</code></pre>
<h2 id="torii">Torii</h2>
<p>We will install and use the Torii addon to manage our authentication sessions:</p>
<pre><code class="language-bash">ember install torii
</code></pre>
<p>We will need to manually create an adapter so that Torii and EmberFire play nice with each other:</p>
<pre><code class="language-javascript">// app/torii-adapters/application.js

import Ember from 'ember';
import ToriiFirebaseAdapter from 'emberfire/torii-adapters/firebase';

export default ToriiFirebaseAdapter.extend({
  firebase: Ember.inject.service()
});
</code></pre>
<p>Here we're extending the Torii adapter that EmberFire already provides for us and injecting the Firebase service that we previously set up.</p>
<p>Then, once again in the app's config, we need to set the name of the session service that Torii provides:</p>
<pre><code class="language-javascript">// config/environment.js

module.exports = function(environment) {
  var ENV = {
//...
    firebase: 'https://ember-firebase-demo.firebaseio.com/',
    torii: { sessionServiceName: 'session' },
    baseUrl: '/',
//...
  }
}
</code></pre>
<p>Here we set it to &quot;session.&quot; Torii will automatically inject this service into our routes and controllers.</p>
<h2 id="bootstrapandfontawesome">Bootstrap and Font Awesome</h2>
<p>In order to make our Ember Firebase Demo app look pretty, we'll install the <a href="https://github.com/kaliber5/ember-bootstrap">Bootstrap</a> and <a href="https://github.com/martndemus/ember-cli-font-awesome">Font Awesome</a> addons:</p>
<pre><code class="language-bash">ember install ember-bootstrap
ember install ember-cli-font-awesome
</code></pre>
<h1 id="buildingtheapp">Building the App</h1>
<p>We've got everything installed and configured, so let's start our app:</p>
<pre><code class="language-bash">ember serve
</code></pre>
<p>When you point your browser to <a href="http://localhost:4200">http://localhost:4200</a>, you should see &quot;Welcome to Ember.&quot;</p>
<h2 id="thebasictemplates">The Basic Templates</h2>
<p>Let's remove the welcome message and give our application a navigation bar:</p>
<pre><code class="language-html">// app/templates/application.hbs

&lt;nav class='navbar navbar-default'&gt;
    &lt;div class='container'&gt;
        &lt;div class='navbar-brand'&gt;EmberFirebaseDemo&lt;/div&gt;
    &lt;/div&gt;
&lt;/nav&gt;  
&lt;div class='container'&gt;
    {{outlet}}
&lt;/div&gt;
</code></pre>
<p>Now let's create some content for the index route so we're not just staring at a mostly blank page:</p>
<pre><code class="language-html">// app/templates/index.hbs

&lt;div class='page-header'&gt;
    &lt;h1&gt;You must be signed in to use this app&lt;/h1&gt;
&lt;/div&gt;
</code></pre>
<h2 id="signingup">Signing Up</h2>
<p>The first bit of functionality we need to create is allowing new users to sign up. First, we'll need to generate a new controller:</p>
<pre><code class="language-bash">ember generate controller sign-up
</code></pre>
<p>This generated an <code>app/controllers/sign-up.js</code> scaffolding file. Let's create a <code>signUp</code> action in that file:</p>
<pre><code class="language-javascript">// app/controllers/sign-up.js

import Ember from 'ember';

export default Ember.Controller.extend({
  firebase: Ember.inject.service(),
  actions: {
    signUp() {
      let controller = this;
      this.get('firebase').createUser({
        email: this.get('email') || '',
        password: this.get('password') || '',
      }, (error, data) =&gt; {
        if (error) {
          console.log(error);
        } else {
          controller.set('email', null);
          controller.set('password', null);
        }
      });
    }
  }
});
</code></pre>
<p>Here we inject the <code>firebase</code> service. Then, in the <code>signUp</code> action, we get the service we just injected and pass in the user's email and password, along with a callback, into its <code>createUser</code> method. In the callback we check to see if there were any errors. (For the sake of expediency in this demo, all of our error handling will be in the form of logging to the console.) If there were no errors, the user is now signed up, so we clear the <code>email</code> and <code>password</code> properties.</p>
<p>But where are the email and password values coming from? We'll have to create a form, so that the user can provide them.</p>
<p>Generate a new route:</p>
<pre><code class="language-bash">ember generate route sign-up
</code></pre>
<p>This will add a <code>sign-up</code> route to <code>app/router.js</code> as well as create scaffolding route and template files. Let's update the template it created:</p>
<pre><code class="language-html">// app/templates/sign-up.hbs

&lt;div class='page-header'&gt;
    &lt;h1&gt;Sign Up&lt;/h1&gt;
&lt;/div&gt;
{{input
    type='text'
    class='form-control'
    value=email
    placeholder='email'
}}
{{input
    type='password'
    class='form-control'
    value=password
    placeholder='password'
}}
&lt;button
    class='btn btn-default'
    {{action 'signUp'}}
&gt;
    {{fa-icon 'user-plus'}} Sign Up
&lt;/button&gt;
</code></pre>
<p>We created email and password fields and a button with a <code>signUp</code> action.</p>
<aside>For bonus points, you can add a password confirmation field in the template and ensure that both password fields match before calling `createUser` in the controller.</aside>
<p>Now let's add a Sign Up link to our index template:</p>
<pre><code class="language-html">// app/templates/index.hbs

&lt;div class='page-header'&gt;
    &lt;h1&gt;You must be signed in to use this app&lt;/h1&gt;
&lt;/div&gt;
&lt;div class='list-group'&gt;
    {{#link-to 'sign-up' class='list-group-item'}}
        Sign Up
    {{/link-to}}
&lt;/div&gt;
</code></pre>
<p>So, now we should see a <em>Sign Up</em> link on our index page. When we click it, we'll be taken to the <code>sign-up</code> route and presented with a form. When we fill out the form and press the <em>Sign Up</em> button, the form fields should reset if the sign up was successful. You can confirm that a user was created by going back to the <em>Login &amp; Auth</em> tab of your Firebase app's management screen. At the bottom there is a <em>Registered Users</em> table. If you don't see your email address, try hitting <em>refresh list</em>.</p>
<h2 id="signingin">Signing In</h2>
<p>Now that our users can sign up, we need to let them sign in. As with the last step, we'll need to create a controller:</p>
<pre><code class="language-bash">ember generate controller sign-in
</code></pre>
<p>Then we'll create the <code>signIn</code> action:</p>
<pre><code class="language-javascript">// app/controllers/sign-in.js

import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    signIn(provider) {
      let controller = this;
      this.get('session').open('firebase', {
        provider: provider,
        email: this.get('email') || '',
        password: this.get('password') || '',
      }).then(() =&gt; {
        controller.set('email', null);
        controller.set('password', null);
      }, (error) =&gt; {
        console.log(error);
      });
    }
  } 
});
</code></pre>
<p>Here we get the <code>session</code> service (remember, Torii automatically injects it into our routes and controllers) and create a new Firebase session instance by passing in the action's <code>provider</code> parameter and the user's email and password to the <code>open</code> method. On success, we clear the form, and on error we log to the console.</p>
<p>Again, we need a form to collect this information, so let's generate the route:</p>
<pre><code class="language-bash">ember generate route sign-in
</code></pre>
<p>Then we'll update the generated template. It will look remarkably similar to the Sign Up template:</p>
<pre><code class="language-html">// app/templates/sign-in.hbs

&lt;div class='page-header'&gt;
    &lt;h1&gt;Sign In&lt;/h1&gt;
&lt;/div&gt;
{{input
    type='text'
    class='form-control'
    value=email
    placeholder='email'
}}
{{input
    type='password'
    class='form-control'
    value=password
    placeholder='password'
}}
&lt;button
    class='btn btn-default'
    {{action 'signIn' 'password'}}
&gt;
    {{fa-icon 'sign-in'}} Sign In
&lt;/button&gt;
</code></pre>
<p>The notable difference is in the button's action, specifically the additional <code>'password'</code> string parameter. This corresponds to the <code>provider</code> parameter that we saw passed into the <code>signIn</code> action in the controller. This parameter denotes the authentication provider, in this case Firebase's own Email &amp; Password Authentication provider.</p>
<aside>Firebase provides integrations for several other authentication providers, including Google, Facebook, GitHub, etc. See the [documentation](https://www.firebase.com/docs/web/guide/user-auth.html) for details.</aside>
<p>Finally, let's add a Sign In option to our index template:</p>
<pre><code class="language-html">// app/templates/index.hbs

&lt;div class='page-header'&gt;
    &lt;h1&gt;You must be signed in to use this app&lt;/h1&gt;
&lt;/div&gt;
&lt;div class='list-group'&gt;
    {{#link-to 'sign-up' class='list-group-item'}}
        Sign Up
    {{/link-to}}
    {{#link-to 'sign-in' class='list-group-item'}}
        Sign In
    {{/link-to}}
&lt;/div&gt;

</code></pre>
<p>Now you should be able to go to <a href="http://localhost:4200/sign-up">http://localhost:4200/sign-up</a> to create credentials, then go to <a href="http://localhost:4200/sign-in">http://localhost:4200/sign-in</a> to enter those credentials and sign in. If the sign in is successful, the form will clear and you will be an authenticated user.</p>
<h2 id="thesession">The Session</h2>
<p>We just used the Torii <code>session</code> service to create a new session instance with the <code>open</code> method. Let's see what else we can do with it.</p>
<p>I mentioned how Torii automatically injects the <code>session</code> service into our routes and controllers. So, by extension, <code>session</code> is available in our templates, as well. Let's update our sign in template to utilize it:</p>
<pre><code class="language-html">// app/templates/sign-in.hbs

//...
{{#if session.isWorking}}
    &lt;button class='btn btn-default' disabled='disabled'&gt;
        {{fa-icon 'spinner' spin=true}} Signing in...
    &lt;/button&gt;
{{else}}
    &lt;button
        class='btn btn-default'
        {{action 'signIn' 'password'}}
    &gt;
        {{fa-icon 'sign-in'}} Sign In
    &lt;/button&gt;
{{/if}}
</code></pre>
<p>We check the <code>isWorking</code> property of the <code>session</code> service to see if Torii is currently in the process of authenticating a user. If so, we display a disabled <em>Signing In</em> button with a spinner. If not, we display the regular <em>Sign In</em> button.</p>
<p>So now, when we go to <a href="http://localhost:4200/sign-in">http://localhost:4200/sign-in</a>, enter our credentials, and sign in we should see the button change as we wait to be authenticated.</p>
<p>&quot;But wait!&quot; an astute observer might exclaim, &quot;didn't we previously sign in? Shouldn't we still be authenticated?&quot; That's correct. But since the page has refreshed and our app reloaded since then, it has lost track of our session.</p>
<p>So, let's add some functionality to our application route so that whenever our app reloads, our application retrieves the current session:</p>
<pre><code class="language-javascript">// app/routes/application.js

import Ember from 'ember';

export default Ember.Route.extend({
  beforeModel() {
    this.get('session').fetch().catch((error) =&gt; {
      console.log(error);
    });
  }
});
</code></pre>
<p>We've added a <code>beforeModel</code> hook that is executed as the application route is initializing, ie. before any of the other routes. It simply calls <code>fetch</code> on the session service to retrieve the current user's session, if it exists.</p>
<h2 id="signingout">Signing Out</h2>
<p>Let's allow our users to sign out from anywhere inside our app. To do that we'll first need to create an application controller with a <code>signOut</code> action:</p>
<pre><code class="language-javascript">// app/controllers/application.js

import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    signOut() {
      this.get('session').close();
    }
  }
});
</code></pre>
<p>We simply call <code>close</code> on the <code>session</code> service.</p>
<p>Now let's add a <em>Sign Out</em> button to our application template:</p>
<pre><code class="language-html">// app/templates/application.hbs

//...  
    &lt;div class='container'&gt;
        &lt;div class='navbar-brand'&gt;EmberFirebaseDemo&lt;/div&gt;
        &lt;div class='navbar-right'&gt;
            {{#if session.isAuthenticated}}
                &lt;button
                    class='btn btn-default navbar-btn'
                    {{action 'signOut'}}
                &gt;
                    {{fa-icon 'sign-out'}} Sign Out
                &lt;/button&gt;
            {{/if}}
        &lt;/div&gt;
    &lt;/div&gt;
//...
</code></pre>
<p>We used the <code>session</code> service's <code>isAuthenticated</code> property to check to see that the user is signed in before displaying the <em>Sign Out</em> button. Because what's the point of giving the user the option to sign out if they're not even signed in!</p>
<h2 id="welcomepage">Welcome Page</h2>
<p>So, now that our users can sign up, sign in, and sign out, let's create a welcome page for users once they have signed in. First, generate the route:</p>
<pre><code class="language-bash">ember generate route welcome
</code></pre>
<p>Then we update the template to display information about the authenticated user:</p>
<pre><code class="language-html">&lt;div class='page-header'&gt;
    &lt;h1&gt;Welcome, you are signed in!&lt;/h1&gt;
&lt;/div&gt;
&lt;div class='panel panel-default'&gt;
    &lt;div class='panel-heading'&gt;{{session.currentUser.email}}&lt;/div&gt;
    &lt;div class='panel-body'&gt;
        &lt;img src='{{session.currentUser.profileImageURL}}' /&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>Now, if you're signed in and you go to <a href="http://localhost:4200/welcome">http://localhost:4200/welcome</a>, you should see a panels with your email address in the header and your avatar in the body.</p>
<h2 id="redirection">Redirection</h2>
<p>Depending on what actions our users take and whether or not they are signed in, we want them to be redirected to various routes of our application:</p>
<ul>
<li>When they successfully sign up, they should be taken to the Sign In route</li>
<li>When they successfully sign in, they should be taken to the Welcome route</li>
<li>When they sign out, they should be taken to the index route</li>
<li>When they try to access the Sign Up and Sign In routes while authenticated, they should instead be taken to the Welcome route</li>
<li>When they try to access the Welcome route while not authenticated, they should instead be taken to the Sign In route</li>
</ul>
<h3 id="actionbasedredirection">Action-Based Redirection</h3>
<p>Let's start with the redirection that happens when the user completes an action.</p>
<p>Let's add redirection to the <code>sign-in</code> route in the <code>signUp</code> action:</p>
<pre><code class="language-javascript">// app/controllers/sign-up.js

//...
    signUp() {
      let controller = this;
      this.get('firebase').createUser({
        email: this.get('email') || '',
        password: this.get('password') || '',
      }, (error, data) =&gt; {
        if (error) {
          console.log(error);
        } else {
          controller.set('email', null);
          controller.set('password', null);
          controller.transitionToRoute('sign-in');
        }
      });
    }
//...
});
</code></pre>
<p>And add redirection to the <code>welcome</code> route in the <code>signIn</code> action:</p>
<pre><code class="language-javascript">// app/controllers/sign-in.js

//...
    signIn(provider) {
      let controller = this;
      this.get('session').open('firebase', {
        provider: provider,
        email: this.get('email') || '',
        password: this.get('password') || '',
      }).then(() =&gt; {
        controller.set('email', null);
        controller.set('password', null);
        controller.transitionToRoute('welcome');
      }, (error) =&gt; {
        console.log(error);
      });
    }
//...
});
</code></pre>
<p>And then add redirection to the <code>/</code> route in the <code>signOut</code> action:</p>
<pre><code class="language-javascript">// app/controllers/application.js

//...
    signOut() {
      this.get('session').close();
      this.transitionToRoute('/');
    }
//...
</code></pre>
<h3 id="authenticationbasedredirection">Authentication-Based Redirection</h3>
<p>Now let's add in some redirection that occurs based on the user's authentication status.</p>
<p>Let's add redirection to the <code>welcome</code> route when an authenticated user attempts to go to the <code>sign-up</code> or <code>sign-in</code> routes; update both <code>app/routes/sign-up.js</code> and <code>app/routes/sign-in.js</code>:</p>
<pre><code class="language-javascript">// app/routes/sign-up.js and app/routes/sign-in.js

import Ember from 'ember';

export default Ember.Route.extend({
  beforeModel() {
    if (this.get('session.isAuthenticated')) {
      this.transitionTo('welcome');
    }
  }
});
</code></pre>
<p>Here we're checking the <code>isAuthenticated</code> property of the session service in the <code>beforeModel</code> hook, while the route is initializing. If the user is already signed in, they will be redirected to the <code>welcome</code> route.</p>
<p>Now let's add redirection to the <code>/</code> route when a non authenticated user attempts to navigate to the <code>welcome</code> route. This is going to be a little bit more indirect than our previous updates. First, we're going to add an <code>accessDenied</code> action to our application's route:</p>
<pre><code class="language-javascript">// app/routes/application.js
import Ember from 'ember';

export default Ember.Route.extend({
  beforeModel() {
    return this.get('session').fetch();
  },

  actions: {
    accessDenied() {
      this.transitionTo('/');
    },
  },
});
</code></pre>
<p>All this action does is redirect to the index route. So, how do we call this action when non authenticated users try to access routes that require authentication? Well, Torii provides us with a special route method called <code>authenticatedRoute</code> that we can use in our router map. If a non authenticated user navigates to an authenticated route, Torii will invoke the <code>accessDenied</code> action.</p>
<p>Let's update the <code>welcome</code> route to be an authenticated route:</p>
<pre><code class="language-javascript">// app/router.js

//...
Router.map(function() {
  this.route('sign-up');
  this.route('sign-in');
  this.authenticatedRoute('welcome');
});
//...
</code></pre>
<p>Try navigating to each route while signed in and then again when signed out. You should be redirected appropriately.</p>
<h2 id="whateveritsactuallysupposedtodo">Whatever It's Actually Supposed to Do</h2>
<p>So, now you have an Ember application with user authentication! It's a little rough around the edges and not quite production-ready, to be sure; you'll want to do some input validation, put some error handling in place, and update the project's content security policy in your config for starters. But now you can start focusing on whatever it is that your app is actually supposed to do.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Changing hosting providers]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Literally minutes after I started splashing this newly launched freelance portfolio site all over my social media yesterday, my hosting provider went down. What luck, huh?</p>
<p>I should have anticipated it, though. <a href="http://linode.com">Linode</a>, my hosting provider, had been under attack for the past week or so (you can read all</p>]]></description><link>https://zachgarwood.blog/changing-hosting-providers/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3e0</guid><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Wed, 06 Jan 2016 23:57:17 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Literally minutes after I started splashing this newly launched freelance portfolio site all over my social media yesterday, my hosting provider went down. What luck, huh?</p>
<p>I should have anticipated it, though. <a href="http://linode.com">Linode</a>, my hosting provider, had been under attack for the past week or so (you can read all about it on their <a href="https://linode.statuspage.io/">status page</a>), and even when I'd been setting this site up, I'd experienced some intermittent outages.</p>
<p>So, I spent some time this morning migrating the site to a new hosting provider, <a href="http://digitalocean.com">DigitalOcean</a>, and cancelled my service with Linode. I feel a little bad abandoning them after I've used their service for years (mainly just futzing around with side projects). After all, it's not their fault that some ne'er-do-wells have a vendetta against them and have been trying to bring their service down day after day. In the end, loyalty is great; however, if I'm going to rely on this site to help me reach potential clients and make a living, I can't pay them to host a site that no one can see.</p>
<p>So far I'm pretty impressed with DigitalOcean. The interface is clean and easy to understand, and they've got pretty good documentation. They even have a cheaper hosting option than what I was using at Linode that better serves my needs. All in all, I'd say this was a change for the better.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Object Version System]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Written in Javascript, using <a href="http://emberjs.com/">Ember</a> with the <a href="https://kaliber5.github.io/ember-bootstrap/">Bootstrap</a> addon for the interface and <a href="http://expressjs.com/">Express</a> and <a href="https://www.mongodb.org/">MongoDB</a> for serving and managing the data, this commission was a simple UI to be used on a company's intranet for viewing the differences between various versions of JSON objects.</p>
<p>The user clicks on an</p>]]></description><link>https://zachgarwood.blog/object-version-system/</link><guid isPermaLink="false">5d17d5e9826d8c7b753af3df</guid><category><![CDATA[Ember]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Zach Garwood]]></dc:creator><pubDate>Tue, 05 Jan 2016 19:45:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Written in Javascript, using <a href="http://emberjs.com/">Ember</a> with the <a href="https://kaliber5.github.io/ember-bootstrap/">Bootstrap</a> addon for the interface and <a href="http://expressjs.com/">Express</a> and <a href="https://www.mongodb.org/">MongoDB</a> for serving and managing the data, this commission was a simple UI to be used on a company's intranet for viewing the differences between various versions of JSON objects.</p>
<p>The user clicks on an object ID in the <em>Objects</em> panel on the left and is shown a list of revision dates for that object. Checking one or more dates displays the data for the revisions in the <em>Data</em> panel on the right. When a given key does not appear in a revision, the corresponding table cell is blank. When a value for a particular key has changed from one revision to the next, the corresponding table cell is highlighted in the latter revision.</p>
<p>See the <a href="https://github.com/zachgarwood/object-version-system">code</a> on GitHub.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>