<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Matt Beedle</title>
 <link href="http://blog.mattbeedle.name/atom.xml" rel="self"/>
 <link href="http://blog.mattbeedle.name/"/>
 <updated>2015-09-27T10:35:22+00:00</updated>
 <id>http://blog.mattbeedle.name</id>
 <author>
   <name>Matt Beedle</name>
 </author>

 
 <entry>
   <title>Morning Routine</title>
   <link href="http://blog.mattbeedle.name/posts/morning-routine"/>
   <updated>2015-09-27T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/morning-routine</id>
   <content type="html">&lt;p&gt;I&amp;rsquo;ve been struggling a bit with productivity at recently, working for a startup, from home, with
a 1 year old child. 9am I wake up, 2 hours later than I would like, then
after a shower and 30 minutes work it&amp;rsquo;s time for family breakfast. Then my
girlfriend is in the shower and I need to keep an eye on my son. Another hour of
work, then it&amp;rsquo;s lunch time. Another couple of hours after that it&amp;rsquo;s dinner,
getting my kid to bed, etc. Now it&amp;rsquo;s late, I spend several tired, less
productive hours trying to cram a day of work in. I go to bed late and tired.
Rinse and repeat. This routine has been really affecting my productivity,
health, fitness, etc.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve read a lot
about how important good habits and a morning routine are for success. A good
morning routine sets you up to win at your day and at life in general.
Since this week I&amp;rsquo;ve implemented a new routine and it&amp;rsquo;s amazing. I&amp;rsquo;m now up
every morning at &lt;strong&gt;5:30am&lt;/strong&gt; and started &lt;a href=&quot;https://en.wikipedia.org/wiki/Intermittent_fasting&quot;&gt;intermittent
fasting&lt;/a&gt; again.&lt;/p&gt;

&lt;h2&gt;My Routine&lt;/h2&gt;

&lt;h3&gt;1. Wake up at 5:30am and drink a large glass of water&lt;/h3&gt;

&lt;p&gt;When you wake up, whether you feel it or not, your body is dehydrated. Drinking
a large glass of water not only rehydrates you, but apparently also has numerous
thereputic effects. I leave a glass full next to my bed before I sleep so I can
have it at room temperature instead of having to drinking freezing water
straight from the cooler.&lt;/p&gt;

&lt;h3&gt;2. Have a freezing cold shower (5 minutes)&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://impossiblehq.com/cold-shower-health-benefits/&quot;&gt;Benefits of a cold
shower&lt;/a&gt;
include better immune system, fat loss, improved
circulation, temperature regulation, relief from symtoms of depression, health
skin/hair, testosterone increase, fertility increase, energy increase, lymphatic
movement, inflammation decrease, better breathing, better sleep, tolerance to
stress. Wow, they are healthy. Also hard to start doing. I&amp;rsquo;m pretty sure the
neighbours could hear me screaming on the first day. I&amp;rsquo;ve already got much more
used to them now though after only a few days.&lt;/p&gt;

&lt;h3&gt;3. Brush teeth / get dressed (2 minutes)&lt;/h3&gt;

&lt;p&gt;Even working at home, it&amp;rsquo;s important to have the feeling of &amp;ldquo;going to work&amp;rdquo;.
I wear pretty much the same clothes every day, so there&amp;rsquo;s no decision making
there in the morning.&lt;/p&gt;

&lt;h3&gt;4. Meditate (15 minutes)&lt;/h3&gt;

&lt;p&gt;I use &lt;a href=&quot;https://www.headspace.com/&quot;&gt;headspace&lt;/a&gt; for this, although I&amp;rsquo;m thinking of investing in a &lt;a href=&quot;http://www.choosemuse.com/&quot;&gt;Muse headband&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;5. Brew a bullet-proof coffee (10 minutes)&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.bulletproofexec.com/how-to-make-your-coffee-bulletproof-and-your-morning-too/&quot;&gt;This
stuff&lt;/a&gt;
is really great. It gives me a huge morning energy/concentration boost. That
being said I do seem to get less of a boost now than I used to. Maybe it&amp;rsquo;s one
of those slippery slope things and I&amp;rsquo;ll end up doing morning lines of speed by
next year. I brew
my coffee using a stove top espresso maker. While that&amp;rsquo;s going on I do the
washing up if there is any.&lt;/p&gt;

&lt;h3&gt;6. Read something (20 minutes)&lt;/h3&gt;

&lt;p&gt;I like to read something technical in the morning when my mind is most
receptive. At present I&amp;rsquo;m reading &lt;a href=&quot;https://leanpub.com/javascript-allonge&quot;&gt;JavaScript
Allongé&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;7. Write something (20 minutes)&lt;/h3&gt;

&lt;p&gt;I always used to be annoyed at myself for not writing any blog posts. Now, with
20 minutes per morning I should be able to pump out at least 1 per week.
Hopefully I&amp;rsquo;ll get a bit faster at this with practice. Maybe now I&amp;rsquo;ll also find
time again to continue writing the EmberJS/Rails book I started over a year
ago.&lt;/p&gt;

&lt;h3&gt;8. Daily goals (5 minutes)&lt;/h3&gt;

&lt;p&gt;I review all of my tasks in &lt;a href=&quot;https://www.omnigroup.com/omnifocus/&quot;&gt;OmniFocus&lt;/a&gt;.
This used to take a long time but now I do it daily it&amp;rsquo;s really fast. I pick
3 things that need to get done for that day and flag them. I also do have
a bunch of recurring flagged tasks in here.&lt;/p&gt;

&lt;h3&gt;Start working&lt;/h3&gt;

&lt;p&gt;In under an 1.5 hours I&amp;rsquo;ve already got a load of things done that I never
normally have time for and I have a blissful 5 hours to work with no
interuptions until workout/lunch time. During this working stretch I switch on &amp;ldquo;Do Not Disturb&amp;rdquo; in Notification Center,
turn off &lt;a href=&quot;http://airmailapp.com/&quot;&gt;AirMail&lt;/a&gt;/&lt;a href=&quot;http://tapbots.com/tweetbot/mac/&quot;&gt;TweetBot&lt;/a&gt;/etc,
and I work in &lt;a href=&quot;https://en.wikipedia.org/wiki/Pomodoro_Technique&quot;&gt;Pomodoros&lt;/a&gt;
using &lt;a href=&quot;http://www.publicspace.net/Vitamin-R/&quot;&gt;Vitamin-R&lt;/a&gt;
At the moment I&amp;rsquo;m working for a startup
(&lt;a href=&quot;https://www.groovehq.com&quot;&gt;Groove&lt;/a&gt; where the development tasks are nicely
planned out already in PivotalTracker and Github. If I were doing some other job
I would probably need to add a day planning phase where
I actually prioritise and plan out the tasks that I need to run through that day.&lt;/p&gt;

&lt;p&gt;In conclusion I&amp;rsquo;m so far very happy with this experiment and can definitely see
myself sticking to it. You should definitely give it a go too.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Git Cleanup</title>
   <link href="http://blog.mattbeedle.name/posts/git-cleanup"/>
   <updated>2014-08-16T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/git-cleanup</id>
   <content type="html">&lt;p&gt;My normal development workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new feature branch on my local machine for whatever project I am
working on&lt;/li&gt;
&lt;li&gt;Build the feature (testing first!)&lt;/li&gt;
&lt;li&gt;Push the working feature to GitHub&lt;/li&gt;
&lt;li&gt;Create a pull request&lt;/li&gt;
&lt;li&gt;Pull request is reviewed/signed off&lt;/li&gt;
&lt;li&gt;Click the &amp;ldquo;Merge&amp;rdquo; button on GitHub and then &amp;ldquo;Delete branch&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Checkout master on my local machine and pull the latest master from GitHub&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I should probably remember to always delete the feature branch on my local
machine after it&amp;rsquo;s merged on GitHub. I never manage this. Sometimes I don&amp;rsquo;t do
this for a very long time and end up with 30+ branches. Then I don&amp;rsquo;t remember
which ones are merged so I don&amp;rsquo;t know which ones I can delete. Things get messy.
So I wrote a quick &lt;a href=&quot;http://githowto.com/aliases&quot;&gt;Git Alias&lt;/a&gt; to help me out. To
create the alias run the following command from your terminal:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git config --global alias.cleanup &#39;!git checkout master &amp;amp;&amp;amp; git branch --merged | grep -v &quot;*&quot; | xargs -n 1 git branch -d&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This alias will automatically delete all branches which have already been merged
with master. Just run it from the root of your Git project.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git cleanup
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I hope this helps simplify your life as it did mine.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ember Data ISO Date Transform</title>
   <link href="http://blog.mattbeedle.name/posts/ember-data-isodate-transform"/>
   <updated>2014-07-25T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/ember-data-isodate-transform</id>
   <content type="html">&lt;p&gt;Most of my EmberJS projects use a datetime field somewhere on the backend.
Reading them from the API is easy using a &amp;lsquo;date&amp;rsquo; attribute type, but this
doesn&amp;rsquo;t serialize to a very API friendly format. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;new Date().toString()
&quot;Wed Aug 06 2014 12:39:29 GMT+0200 (CEST)&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;My API expects
to receive date times in &lt;a href=&quot;http://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601
format&lt;/a&gt;. We can easily achieve this using
&lt;a href=&quot;http://momentjs.com&quot;&gt;MomentJS&lt;/a&gt; and an
an &lt;a href=&quot;http://emberjs.com/api/data/classes/DS.Transform.html&quot;&gt;Ember Data
Transform&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;bower install --save moment&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;app/transforms/isodate.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember-data&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;IsodateTransform = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# The deserialize function just transforms the string it receives from the&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# server JSON response into a date.&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;deserialize: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(serialized) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;serialized&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;serialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# The serialize function takes the value of the attribute on the model and&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# transforms it into a nice ISO date to send to our server.&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;serialize: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(deserialized) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deserialized&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deserialized&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deserialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# I&amp;#39;m using the European date format here. This is how date strings are&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# set on my models by my datetimepicker inputs. US readers may be able&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# to leave this second argument out&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deserialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;DD/MM/YY h:mm a&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;IsodateTransform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now in any models where it is needed, you can use your isodate transform.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/models/user.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember-data&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;User = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;createdAt: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;isodate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Ember CLI Bootstrap Modals</title>
   <link href="http://blog.mattbeedle.name/posts/ember-cli-bootstrap-modals"/>
   <updated>2014-07-18T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/ember-cli-bootstrap-modals</id>
   <content type="html">&lt;p&gt;It&amp;rsquo;s really easy to create reusable modal code to integrate
&lt;a href=&quot;http://getbootstrap.com/javascript/#modals&quot;&gt;Twitter Bootstrap modals&lt;/a&gt; into
&lt;a href=&quot;http://emberjs.com/&quot;&gt;EmberJS&lt;/a&gt; projects. Here&amp;rsquo;s how to do it:&lt;/p&gt;

&lt;h2&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;Demo at
&lt;a href=&quot;http://ember-cli-bootstrap-modal.herokuapp.com/&quot;&gt;http://ember-cli-bootstrap-modal.herokuapp.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code at
&lt;a href=&quot;https://github.com/mattbeedle/ember-cli-bootstrap-modal-example&quot;&gt;https://github.com/mattbeedle/ember-cli-bootstrap-modal-example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;The Modal code&lt;/h2&gt;

&lt;p&gt;The modal code is all the code that our modals will be built on top
of. It consists of a &lt;code&gt;ModalController&lt;/code&gt;, &lt;code&gt;ModalView&lt;/code&gt;, &lt;code&gt;openModal&lt;/code&gt; and
&lt;code&gt;closeModal&lt;/code&gt; actions, and a &lt;code&gt;modal&lt;/code&gt; outlet. Links to demo app and
working code are at the bottom of the article.&lt;/p&gt;

&lt;p&gt;First, let&amp;rsquo;s create a basic application template with a modal outlet into which
our modals will be rendered:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/templates/application.hbs&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Bootstrap Modal with Ember CLI examples&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

{{outlet}}

{{outlet &amp;quot;modal&amp;quot;}}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we will define a &lt;code&gt;ModalView&lt;/code&gt;. All modal views will inherit from this
view. It ensures that modal settings are consistent across all modals.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/views/modal.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;ModalView = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;tagName: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;div&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;classNames: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;modal&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# didInsertElement is run once the element of the view has been inserted into&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# the DOM&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# http://emberjs.com/api/classes/Ember.View.html#event_didInsertElement&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;didInsertElement: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# First set the div id to &amp;quot;modal&amp;quot;. &amp;quot;@$()&amp;quot; is the shortcut to get the view&amp;#39;s&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# jQuery element&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;@$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;modal&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Now set up the modal&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;@$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modal&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;keyboard: &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;backdrop: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;static&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Now show the modal&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;@$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;show&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# This is run when the element of the view is going to be destroyed. We&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# override it here to hide the modal first.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# http://emberjs.com/api/classes/Ember.View.html#event_willDestroyElement&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;willDestroyElement: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;@$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modal&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;hide&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ModalView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we define a &lt;code&gt;ModalController&lt;/code&gt;. This will handle the cancel action. All other
modal controllers will inherit from this.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/controllers/modal.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;ModalController = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ObjectController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;actions:&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;cancel: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# If the controller @content is set, then we need to roll it back to avoid&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# inconsistent state between client and server.&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;@content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rollback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;@content&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;# Now we send &amp;quot;closeModal&amp;quot; event to bubble up to the application route&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;@send&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;closeModal&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ModalController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we need to define the global &lt;code&gt;openModal&lt;/code&gt; and &lt;code&gt;closeModal&lt;/code&gt; actions.
We will do this in &lt;code&gt;ApplicationRoute&lt;/code&gt; as everything bubbles up to here in
the end.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/routes/application.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;ApplicationRoute = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;actions:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# This takes one argument; The template to render. It then renders it into&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The modal outlet which we defined in the application template.&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;openModal: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(modal) -&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;@render&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;into: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;application&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;outlet: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;modal&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# This handles removing the modal. It simply disconnects the modal outlet to&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# remove the modal. When this happens the &amp;quot;willDestroyElement&amp;quot; function will&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# be called on the ModalView, telling it to close the modal.&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;closeModal: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;@disconnectOutlet&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;outlet: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;modal&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;parentView: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;application&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ApplicationRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Building our first modal&lt;/h2&gt;

&lt;p&gt;At this point all of the code to handle modals is complete. Now we can actually
create our first modal. Let&amp;rsquo;s do this with an action fired from our index
template.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/templates/index.hbs&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;openConfirmationModal&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Confirmation Modal&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We will create an &lt;code&gt;IndexRoute&lt;/code&gt; to handle the &lt;code&gt;openConfirmationModal&lt;/code&gt;
action.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/routes/index.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;IndexRoute = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;actions:&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;openConfirmationModal: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The &amp;quot;openModal&amp;quot; event will bubble up to the ApplicationRoute and be&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# handled there.&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;@send&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;openModal&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;confirmation/new&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;IndexRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We will need a confirmation/new template now to be rendered.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/templates/confirmation/new.hbs&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;modal-dialog&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;modal-content&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;modal-header&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;close&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;button&amp;quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;cancel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;x&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;h4&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;modal-title&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Confirm&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;modal-body&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      Are you sure about this?!?!
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;modal-footer&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;btn btn-default&amp;quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;cancel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Nope&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;btn btn-danger&amp;quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;confirm&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;on=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Yes, do it!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we will need to create a &lt;code&gt;ConfirmationNewController&lt;/code&gt; to handle
the events from the confirmation/new template.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/controllers/confirmation/new.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ModalController&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember-cli-bootstrap-modal-example/controllers/modal&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# We inherit from ModalController to get the &amp;quot;cancel&amp;quot; action.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ConfirmationNewController = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ModalController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;actions:&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;confirm: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;OK, it will be done!&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;@send&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;closeModal&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfirmationNewController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Finall we must create a &lt;code&gt;ConfirmationNewView&lt;/code&gt; that extends &lt;code&gt;ModalView&lt;/code&gt;
to get all of the modal view functionality.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/views/confirmation/new.coffee&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ModalView&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;ember-cli-bootstrap-modal-example/views/modal&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;ConfirmationNewView = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ModalView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfirmationNewView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Notes &amp;amp; links&lt;/h2&gt;

&lt;p&gt;So that&amp;rsquo;s it. Simple Bootstrap modals in EmberJS. I&amp;rsquo;ve created a demo app and
published it to GitHub. It includes a confirm modal, information modal and
a form modal (using ember-easyForm, ember-validations and ember-data
LocalStorage).&lt;/p&gt;

&lt;p&gt;Demo at
&lt;a href=&quot;http://ember-cli-bootstrap-modal.herokuapp.com/&quot;&gt;http://ember-cli-bootstrap-modal.herokuapp.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code at
&lt;a href=&quot;https://github.com/mattbeedle/ember-cli-bootstrap-modal-example&quot;&gt;https://github.com/mattbeedle/ember-cli-bootstrap-modal-example&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>File Uploads in Ember Data</title>
   <link href="http://blog.mattbeedle.name/posts/file-uploads-in-ember-data"/>
   <updated>2014-06-25T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/file-uploads-in-ember-data</id>
   <content type="html">&lt;p&gt;Recently I&amp;rsquo;ve been working on an EmberJS application (&lt;a href=&quot;http://www.salesflip.com&quot;&gt;SalesFlip&lt;/a&gt; - go register there now) which
needs to allow file uploads. There are a couple of different approaches to this
which I&amp;rsquo;ll discuss here, along with a new one which I would like to propose. If
you are wondering what all the import and export statements are in the examples
below, it&amp;rsquo;s because I&amp;rsquo;m using &lt;a href=&quot;http://iamstef.net/ember-app-kit/&quot;&gt;Ember App
Kit&lt;/a&gt;. You should use it too!&lt;/p&gt;

&lt;h2&gt;HTML5 FileReader API&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FileReader&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/FileReader&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The HTML5 FileReader API is fine for really small file uploads outside of
models. It seems to be the
&lt;a href=&quot;http://stackoverflow.com/questions/19909267/ember-js-value-binding-with-html5-file-upload&quot;&gt;currently&lt;/a&gt;
&lt;a href=&quot;http://stackoverflow.com/questions/9200000/file-upload-with-ember-data?lq=1&quot;&gt;recommended&lt;/a&gt;
&lt;a href=&quot;http://stackoverflow.com/questions/13923122/ember-js-upload-file-component?lq=1&quot;&gt;solution&lt;/a&gt;
&lt;a href=&quot;http://stackoverflow.com/questions/14676546/how-file-upload-with-ember-js?lq=1&quot;&gt;on StackOverflow&lt;/a&gt;.
Just create an UploadFile view and then bind the file attribute to the
relevant attribute in the model. However, the ember-data adapter will then
upload the file as a &lt;a href=&quot;http://en.wikipedia.org/wiki/Data_URI_scheme&quot;&gt;data URI&lt;/a&gt; via JSON.
This proved pretty much useless for me. Anything over around 60k would fail.&lt;/p&gt;

&lt;p&gt;app/models/user.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;User = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;avatar: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;app/routes/users/new.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;UsersNewRoute = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;model: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createRecord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;actions:&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;save: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;@currentModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UsersNewRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;app/templates/users/new.hbs&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;view &amp;quot;upload-file&amp;quot; name=&amp;quot;avatar&amp;quot; fileBinding=&amp;quot;avatar&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;app/views/upload_file.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;UploadFile = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;tagName: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;input&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;attributeBindings: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;file: &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;change: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(e) =&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;reader = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;reader.onload = &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(e) =&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;fileToUpload = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;@set&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileToUpload&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readAsDataURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UploadFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Custom FormData Upload View&lt;/h2&gt;

&lt;p&gt;With this approach (&lt;a href=&quot;http://stackoverflow.com/questions/19620122/ember-with-jquery-file-upload&quot;&gt;adapted from here&lt;/a&gt;)
we define an upload button view which will upload the file on
change. This would require some backend magic to work for new users (ones
without an ID). Perhaps the file could be saved and then associated with the
user when the user is saved.&lt;/p&gt;

&lt;p&gt;app/templates/users/new.hbs&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;view &amp;quot;upload-button&amp;quot; userBinding=&amp;quot;user&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;app/views/upload_button.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;UploadButton = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;tagName: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;input&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;attributeBindings: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;originalText: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;Upload Finished Product&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;uploadingText: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;Busy Uploading...&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;newItemHandler: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(data) -&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;controller.store&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;item&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;preUpload: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;parent = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;.fileupload-addbutton&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;upload = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;@get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;uploadingText&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;disabled&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;cursor&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;disabled&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;disabled&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;postUpload: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;parent = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;.fileupload-addbutton&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;form = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#fake_form_for_reset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;orig = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;@get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;originalText&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;disabled&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;cursor&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;pointer&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeAttr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;disabled&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;change: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(e) -&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;formData = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;@preUpload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;@get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;user.id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;url: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/file_upload_handler/&amp;#39;&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Ajax events&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;success: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(data) =&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;@postUpload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;@newItemHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;error: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;@postUpload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;Failure&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Form data&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;data: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Options to tell jQuery not to process data or worry about content-type.&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;cache: &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;contentType: &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;processData: &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UploadButton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Ember Data FormData Adapter&lt;/h2&gt;

&lt;p&gt;This is the approach that I have settled on. I created
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects#Sending_files_using_a_FormData_object&quot;&gt;FormData&lt;/a&gt;
Adapter which is used by any models which require file upload. Using this
approach, adding file uploads to another file is just a matter of creating a new
adapter for it which extends the FileUpload adapter. Although I haven&amp;rsquo;t tried
it, it should be easy to combine this approach with the HTML5
File Reader approach to generate image previews and validate file information
before uploading.&lt;/p&gt;

&lt;p&gt;First define a transform so that files are left untouched&lt;/p&gt;

&lt;p&gt;app/transforms/file.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;FileTransform = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;serialize: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(jsonData) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;jsonData&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;deserialize: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(externalData) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;externalData&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FileTransform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Use the newly defined &amp;ldquo;file&amp;rdquo; attribute type&lt;/p&gt;

&lt;p&gt;app/models/user.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;User = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;avatar: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create a FileUpload input. This is what assigns the file to the model&lt;/p&gt;

&lt;p&gt;app/views/file_upload.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;FileUploadView = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;content: &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;change: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(event) -&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;@set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;@set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FileUploadView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;app/templates/users/new.hbs&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;view &amp;quot;file-upload&amp;quot; contentBinding=&amp;quot;avatar&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create a FormDataAdapter. This is what handles uploading the data via FormData
instead of the default JSON.&lt;/p&gt;

&lt;p&gt;app/adapters/form_data.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ApplicationAdapter&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;appkit/adapters/application&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;get = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;FormDataAdapter = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ApplicationAdapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;ajaxOptions: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(url, type, hash) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;hash = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;hash.url = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;hash.type = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;hash.dataType = &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;json&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;hash.context = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;hash.processData = &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;hash.contentType = &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;fd = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;root = &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

      &lt;span class=&quot;nv&quot;&gt;hash.data = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fd&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;headers = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;hash.beforeSend = &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(xhr) -&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Ember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setRequestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormDataAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create a UserAdapter for the User model to use&lt;/p&gt;

&lt;p&gt;app/adapters/user.coffee&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coffeescript&quot; data-lang=&quot;coffeescript&quot;&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormDataAdapter&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;appkit/adapters/form_data&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;UserAdapter = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;FormDataAdapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>USDA Nutrient Database Web Service</title>
   <link href="http://blog.mattbeedle.name/posts/usda-nutrient-database-web-service"/>
   <updated>2014-05-30T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/usda-nutrient-database-web-service</id>
   <content type="html">&lt;p&gt;The US Department of Agriculture provides a fairly comprehensive database of
foods and their nutritional information. However, I think they don&amp;rsquo;t really want
anyone to use it, as it&amp;rsquo;s only available as separate US-ASCII text files or,
even worse, an MS-Access database.&lt;/p&gt;

&lt;p&gt;Some time ago I found myself needing this
data in a web app, so I built the &lt;a href=&quot;https://github.com/mattbeedle/usda-nutrient-database&quot;&gt;USDA Nutrient
Database&lt;/a&gt; gem. It&amp;rsquo;s very
simple, and basically just downloads and imports the text files into your
application database.&lt;/p&gt;

&lt;h2&gt;The Web Service&lt;/h2&gt;

&lt;p&gt;Recently &lt;a href=&quot;https://twitter.com/coreyitguy&quot;&gt;Corey Martin&lt;/a&gt;
wrote a &lt;a href=&quot;http://aspiringwebdev.com/a-smarter-nutrition-label/&quot;&gt;blog post&lt;/a&gt; about
using my gem along with some others to build &lt;a href=&quot;http://www.cooksmarts.com/weekly-meal-plan-service/nutrition/about-nutrition-label/#.U1QuYeZdWdY&quot;&gt;smarter nutrition
labels&lt;/a&gt;
for &lt;a href=&quot;http://www.cooksmarts.com/&quot;&gt;CookSmarts&lt;/a&gt;. In it he mentions them building
their own server just for serving nutrient information, which eventually
inspired me to build this service. It provides all of the same data, but
additionally adds full text search, pagination, caching, and soon weight
conversions. I&amp;rsquo;ll be keeping the data up to date and will be providing product
support. Feature requests may be sent through UserVoice. Maybe I&amp;rsquo;ll throw an object mapper gem
together in the coming months, to allow people to deal with ruby instead of
JSON. Anyway, you can find the &lt;a href=&quot;http://usda-nutrient-service.mattbeedle.name&quot;&gt;USDA Nutrient Service
here&lt;/a&gt;&amp;hellip; Enjoy&lt;/p&gt;

&lt;h3&gt;TL;DR&lt;/h3&gt;

&lt;p&gt;I built a web service that you can use to query the USDA National Nutrient
Database. You can find the docs at
&lt;a href=&quot;http://docs.usdanutrientservice.apiary.io/&quot;&gt;http://docs.usdanutrientservice.apiary.io/&lt;/a&gt;.
It provides querying, full text searching, pagination, caching, and is also kept up to date with the latest data.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ember App Kit: EMFILE, too many open files</title>
   <link href="http://blog.mattbeedle.name/posts/ember-app-kit-emfile-too-many-open-files"/>
   <updated>2014-01-26T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/ember-app-kit-emfile-too-many-open-files</id>
   <content type="html">&lt;p&gt;Recently I ran into an issue with an Ember App Kit app that I&amp;rsquo;m working on. With livereload enabled the development server is reloaded every time a file is changed, including the bower dependencies installed in vendor. As the bower dependencies grow there is soon a point where the number of files being watched exceeds the allowed limit for the operating system.&lt;/p&gt;

&lt;p&gt;Mac OS X limits the number of open files to 256 by default. There are two types of limit. The &lt;strong&gt;soft limit&lt;/strong&gt; and the &lt;strong&gt;hard limit&lt;/strong&gt;. The soft limit is the currently enforced limit. The hard limit is the maximum value which the soft limit may not exceed. The simple solution is to add the following to your .bashrc:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -n 2048&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If this doesn&amp;rsquo;t work you may need to increase the hard limit. To do this set the following in /etc/sysctl.conf:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;kern.maxfilesperproc&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;166384
kern.maxfiles&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8192&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Deploy Feature Branches to Heroku with Heroku Feature Deployments Gem</title>
   <link href="http://blog.mattbeedle.name/posts/deploy-feature-branches-to-heroku-with-heroku-feature-deployments"/>
   <updated>2014-01-10T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/deploy-feature-branches-to-heroku-with-heroku-feature-deployments</id>
   <content type="html">&lt;h2&gt;The Short Version&lt;/h2&gt;

&lt;p&gt;Deploy the branch you are currently on to Heroku, create a Pull Request, configure DNS and report in PivotalTracker with my &lt;a href=&quot;https://github.com/mattbeedle/heroku_feature_deployments&quot;&gt;Heroku Feature Deployments gem&lt;/a&gt; using the following command.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rake hfd:deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And tear everything down again with:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rake hfd:undeploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;The Long Version&lt;/h2&gt;

&lt;h3&gt;The problem&lt;/h3&gt;

&lt;p&gt;I often find that one major bottleneck in the process of building and shipping
software is testing features. Perhaps 1 feature is pushed to the staging
server for testing, and the feature owner is working with the developer to
iron out any kinks. While this is happening no other developers can push to
staging. Perhaps the other developers don&amp;rsquo;t realise this, and keep pushing and
wiping out each others work before it can be tested. The more things that are
being worked on at once, the worse the problem can get.&lt;/p&gt;

&lt;h3&gt;The (temporary) solution&lt;/h3&gt;

&lt;p&gt;When we developers use git we create a feature branch where all of our changes
go, then create a pull request in GitHub, and then it is merged in after a code
review. Why not also use feature deployments? Heroku is perfect for quickly
deploying temporary sites as long as your &lt;a href=&quot;http://chadfowler.com/blog/2013/06/23/immutable-deployments/&quot;&gt;infrastructure is
immutable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My idea for a process is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer takes the next story/task/feature from the project managment tool&lt;/li&gt;
&lt;li&gt;Developer does required work&lt;/li&gt;
&lt;li&gt;Developer creates a pull request in GitHub&lt;/li&gt;
&lt;li&gt;Developer creates a new Heroku app and deploys the site there&lt;/li&gt;
&lt;li&gt;Developer sets up the DNS so that the site runs on a subdomain.
(http://FEATURE_NAME.mattbeedle.name for example)&lt;/li&gt;
&lt;li&gt;Developer adds this link to the project managment tool and marks the
story/task/feature as ready for testing&lt;/li&gt;
&lt;li&gt;Feature Owner tests the functionality on the subdomain and accepts the work
(hopefully)&lt;/li&gt;
&lt;li&gt;Developer deletes the Heroku app, DNS settings, etc&lt;/li&gt;
&lt;li&gt;Developer marks the pull request as ready for review in GitHub&lt;/li&gt;
&lt;li&gt;Team reviews the pull request and merges into master&lt;/li&gt;
&lt;li&gt;CI server runs tests and if all passes then deploys to the live site&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The only issue with this really is that no-one wants to spend so much time
creating Heroku apps, configuring DNS, etc.&lt;/p&gt;

&lt;p&gt;In order to automate this we&amp;rsquo;ve been using a &lt;a href=&quot;https://github.com/mattbeedle/heroku_feature_deployments&quot;&gt;very simple gem&lt;/a&gt; which I hacked together in a couple of hours and have been gradually adding stuff to for the past year. This gem will handle the following functionality:&lt;/p&gt;

&lt;h4&gt;Deploying&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;creating a Heroku app for the current branch&lt;/li&gt;
&lt;li&gt;adding any required Heroku addons (memcached, redis, etc)&lt;/li&gt;
&lt;li&gt;adding collaborators to Heroku app (the rest of the development team in case
they also need to work)&lt;/li&gt;
&lt;li&gt;configuring DNS to setup a subdomain&lt;/li&gt;
&lt;li&gt;creating a pull request in GitHub&lt;/li&gt;
&lt;li&gt;adding a link to the story in the PivotalTracker&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;All handled by 1 rake task:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rake hfd:deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Tearing Down&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Deleting the Heroku app&lt;/li&gt;
&lt;li&gt;Removing DNS settings&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rake hfd:undeploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This process has worked very well for us so far. The reason it&amp;rsquo;s a temporary
solution is that the gem right now sucks. It&amp;rsquo;s does not have automated tests and
it&amp;rsquo;s tied to Heroku/DNSimple/PivotalTracker. I&amp;rsquo;m going to start working soon on
a hosted configurable deployment tool which integrates with many other services
and has an API so that deployments may be started by a CampFire/HipChat/IRC bot.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Replicate Heroku Production Data in Development</title>
   <link href="http://blog.mattbeedle.name/posts/replicate-heroku-production-data-in-development"/>
   <updated>2013-11-22T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/replicate-heroku-production-data-in-development</id>
   <content type="html">&lt;h2&gt;The Short Version&lt;/h2&gt;

&lt;p&gt;Quickly replicate a Heroku production applications database to your rails
development database with the following command:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;./script/replicate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;The Long Version&lt;/h2&gt;

&lt;p&gt;Sometimes when I have a project in production a bug occurs which I am unable to
replicate on my development machine without a copy of the production data.
Grabbing production data is a task that should be automated. Here&amp;rsquo;s a simple
bash script that I use in all of my heroku apps. Put the file in your rails
script folder:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Running: heroku pgbackups:capture --remote production&amp;quot;&lt;/span&gt;
heroku pgbackups:capture --remote production

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;curl&amp;#39;ing the latest.dump&amp;quot;&lt;/span&gt;
curl -o latest.dump &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;heroku pgbackups:url --remote production&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;restoring the dump&amp;quot;&lt;/span&gt;
pg_restore --verbose --clean --no-acl --no-owner -h localhost -U postgres -d
project_name_development latest.dump

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;removing latest.dump&amp;quot;&lt;/span&gt;
rm latest.dump&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The git remote for my heroku production app is always named &amp;ldquo;production&amp;rdquo;. If
yours is different make sure that you rename it in the script. Also change the
database name to the name of your development database. Finally, make the
script executable:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;chmod+x script/replicate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Initialize</title>
   <link href="http://blog.mattbeedle.name/posts/initialize"/>
   <updated>2013-11-10T00:00:00+00:00</updated>
   <id>http://blog.mattbeedle.name/posts/initialize</id>
   <content type="html">

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Blog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Blog attempt number 5!&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Yet another attempt at a blog. Since 2006 I&amp;rsquo;ve blogged on matt-beedle.com and
then mattbeedle.com. Once with over 1000 UVs per day. Unfortunately I never seem
to manage to keep it up. Both domains were eventually forgotten about and
expired, all the posts only remaining now in the web archive. At least this time
everything is stored in Git on GitHub! Let&amp;rsquo;s see how long it lasts for.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m planning to blog about code and startup experience. Stay tuned.&lt;/p&gt;
</content>
 </entry>
 

</feed>
