Bradley Priest2021-12-01T20:00:41+00:00https://www.bradleypriest.comBradley Priesthello@bradleypriest.comBuilding a Speedy Autocomplete with Postgres on Rails2013-08-27T00:00:00+00:00hhttps://www.bradleypriest.com/2013/08/27/pgsearch_talk
<p>My August <a href="http://www.meetup.com/Singapore-Ruby-Group">RubySG</a> talk about Postgres and <a href="https://github.com/Casecommons/pg_search">pg_search</a></p>
<script async="1" class="speakerdeck-embed" data-id="f7e5fde0f1ba01304d2656f02c133fac" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js">
</script>
<p>I’m planning on doing a writeup sometime soon, so hit me up if you don’t see it in the next few weeks</p>
Ember Tic Tac Toe2013-07-22T00:00:00+00:00hhttps://www.bradleypriest.com/2013/07/22/tic-tac-toe
<p>Every now and then it’s nice to build something completely and utterly useless just for the hell of it.</p>
<p>On Sunday, I sat down and spent a couple of hours building Tic-Tac-Toe in EmberJS.
Although Ember is almost definitely the wrong hammer for the nail, it gave me a chance to refresh the basics.</p>
<p>To check out the final product and code visit <a href="http://bl.ocks.org/bradleypriest/6051289">http://bl.ocks.org/bradleypriest/6051289</a>.</p>
<p>There are plenty of Ember getting started tutorials out there, but they all seem a little too useful for my tastes, so let’s walk through building Tic-Tac-Toe in Ember.</p>
<h2 id="getting-started">Getting Started</h2>
<p>I started out with the <a href="https://jsbin.com/ucanam/239/edit">JSBin template</a> from the official Ember contributing guide.</p>
<p>Firstly, we’re going to need nine objects to represent the tic-tac-toe squares, so we’ll set up the IndexRoute’s model
function to return an array of empty objects.</p>
<p>Then we’ll make sure to set the <code class="language-plaintext highlighter-rouge">App.IndexController</code> to be an <code class="language-plaintext highlighter-rouge">Ember.ArrayController</code>, so we get all the <code class="language-plaintext highlighter-rouge">ArrayProxy</code> goodness.</p>
<p>And we’ll also add some CSS to wrap them into a 3x3 grid.</p>
<figure class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">App</span><span class="p">.</span><span class="nx">IndexRoute</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">Route</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="na">model</span><span class="p">:</span> <span class="kd">function</span><span class="p">(){</span>
<span class="k">return</span> <span class="p">[{},{},{},{},{},{},{},{},{}]</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">App</span><span class="p">.</span><span class="nx">IndexController</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">ArrayController</span><span class="p">.</span><span class="nx">extend</span><span class="p">();</span></code></pre></figure>
<p>Next up let’s set up the basic template and CSS:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><section</span> <span class="na">class=</span><span class="s">"box-wrapper"</span><span class="nt">></span>
{{#each controller}}
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"box"</span><span class="nt">></span>
<span class="nt"></div></span>
{{/each}}
<span class="nt"></section></span></code></pre></figure>
<figure class="highlight"><pre><code class="language-css" data-lang="css"><span class="nc">.box</span> <span class="p">{</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">3px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">100px</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">100px</span> <span class="cp">!important</span><span class="p">;</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">inline-block</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">100px</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">100px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nl">font-family</span><span class="p">:</span> <span class="s1">"Helvetica Neue"</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.box-wrapper</span> <span class="p">{</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">316px</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p><a class="jsbin-embed" href="https://jsbin.com/ucanam/433/embed?live">JS Bin</a></p>
<p>So far, so good. As long as you’re happy drawing on your monitor with a whiteboard marker, we’ve got a perfectly functional board… not so much? Ok, let’s keep going instead.</p>
<h2 id="x-marks-the-spot">X Marks the spot</h2>
<p>A little bit of interactivity perhaps. Ok, well let’s say if you click on a box, we mark it with an X.
So how do we go about that, let’s set a <code class="language-plaintext highlighter-rouge">userSelected</code> flag on the object once you’ve clicked.</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><section</span> <span class="na">class=</span><span class="s">"box-wrapper"</span><span class="nt">></span>
{{#each controller}}
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"box"</span> <span class="err">{{</span><span class="na">action</span> <span class="na">selectBox</span> <span class="na">this</span><span class="err">}}</span><span class="nt">></span>
{{#if userSelected}}
X
{{/if}}
<span class="nt"></div></span>
{{/each}}
<span class="nt"></section></span></code></pre></figure>
<figure class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">App</span><span class="p">.</span><span class="nx">IndexController</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">ArrayController</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="na">selectBox</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">box</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Ember</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">box</span><span class="p">,</span> <span class="dl">'</span><span class="s1">userSelected</span><span class="dl">'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span></code></pre></figure>
<p><a class="jsbin-embed" href="https://jsbin.com/ucanam/431/embed?live">JS Bin</a>
Great, so now when we select a square, we get a nice pretty X in it.
However, it’s pretty easy to win a game when you don’t have an opponent.</p>
<h2 id="player-2">Player 2</h2>
<p>To make sure we don’t get shown up too badly, we’ll start with a pretty dumb AI opponent, it’ll
just pick at random from all of the available moves.</p>
<p>While we’re at it we’ll make things a little easier on ourselves by defining an <code class="language-plaintext highlighter-rouge">App.Box</code> so we can use Ember’s magical computed properties.</p>
<figure class="highlight"><pre><code class="language-js" data-lang="js"> <span class="nx">App</span><span class="p">.</span><span class="nx">Box</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nb">Object</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="na">selected</span><span class="p">:</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">computed</span><span class="p">.</span><span class="nx">or</span><span class="p">(</span><span class="dl">'</span><span class="s1">userSelected</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">computerSelected</span><span class="dl">'</span><span class="p">)</span>
<span class="p">});</span>
<span class="nx">App</span><span class="p">.</span><span class="nx">IndexRoute</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">Route</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="na">model</span><span class="p">:</span> <span class="kd">function</span><span class="p">(){</span>
<span class="k">return</span> <span class="p">[{},{},{},{},{},{},{},{},{}].</span><span class="nx">map</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
<span class="k">return</span> <span class="nx">App</span><span class="p">.</span><span class="nx">Box</span><span class="p">.</span><span class="nx">create</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">});</span></code></pre></figure>
<p>Now let’s add an <code class="language-plaintext highlighter-rouge">unselectedContent</code> property to our controller, and then every time the player
takes a turn the computer will take theirs.</p>
<figure class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">App</span><span class="p">.</span><span class="nx">IndexController</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">ArrayController</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="na">selectBox</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">box</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">box</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">selected</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span>
<span class="nx">Ember</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">box</span><span class="p">,</span> <span class="dl">'</span><span class="s1">userSelected</span><span class="dl">'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">performMove</span><span class="p">();</span>
<span class="p">},</span>
<span class="na">unselectedContent</span> <span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">content</span><span class="dl">'</span><span class="p">).</span><span class="nx">rejectProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">selected</span><span class="dl">'</span><span class="p">)</span>
<span class="p">}.</span><span class="nx">property</span><span class="p">(</span><span class="dl">'</span><span class="s1">@each.selected</span><span class="dl">'</span><span class="p">),</span>
<span class="na">performMove</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">available</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">unselectedContent</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">selected</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">selectMove</span><span class="p">();</span>
<span class="nx">available</span><span class="p">[</span><span class="nx">selected</span><span class="p">].</span><span class="kd">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">computerSelected</span><span class="dl">'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">selectMove</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">available</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">unselectedContent</span><span class="dl">'</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">((</span><span class="nx">available</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">length</span><span class="dl">'</span><span class="p">)</span> <span class="o">*</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()));</span>
<span class="p">}</span>
<span class="p">});</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><section</span> <span class="na">class=</span><span class="s">"box-wrapper"</span><span class="nt">></span>
{{#each controller}}
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"box"</span> <span class="err">{{</span><span class="na">action</span> <span class="na">selectBox</span> <span class="na">this</span><span class="err">}}</span><span class="nt">></span>
{{#if selected}}
{{#if userSelected}}
X
{{/if}}
{{#if computerSelected}}
O
{{/if}}
{{else}}
<span class="ni">&nbsp;</span>
{{/if}}
<span class="nt"></div></span>
{{/each}}
<span class="nt"></section></span></code></pre></figure>
<p>As you can see, we make a quick check to be sure the player has chosen an empty square, and then your opponent randomly chooses one..</p>
<p><a class="jsbin-embed" href="https://jsbin.com/ucanam/434/embed?live">JS Bin</a></p>
<h2 id="winning-is-everything">Winning is Everything</h2>
<p>Ok, now we have a two player tic-tac-toe game. I trust you all to play fair and square, but let’s let the computer decide when the game has been won to be safe.</p>
<p>We’ll start by hardcoding all the possible winning combinations (I’m sure there’s a smarter way of doing this but YOLO)</p>
<figure class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">App</span><span class="p">.</span><span class="nx">IndexController</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">ArrayController</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="na">lines</span><span class="p">:</span> <span class="p">[[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span> <span class="p">[</span><span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">]],</span>
<span class="c1">//...</span>
<span class="p">})</span></code></pre></figure>
<p>And we’ll write some code to compare the player’s square’s indices against all of the possible winning layouts.
We have a function <code class="language-plaintext highlighter-rouge">userWins</code> which calculates all the player’s indices and intersects them with all the possible winning rows.
Basically, if the intersection returns 3 values then the game has been won.</p>
<figure class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">App</span><span class="p">.</span><span class="nx">IndexController</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">ArrayController</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="c1">//...</span>
<span class="na">userIndices</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_indicesForProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">userSelected</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}.</span><span class="nx">property</span><span class="p">(</span><span class="dl">'</span><span class="s1">unselectedContent</span><span class="dl">'</span><span class="p">),</span>
<span class="na">computerIndices</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_indicesForProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">computerSelected</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}.</span><span class="nx">property</span><span class="p">(</span><span class="dl">'</span><span class="s1">unselectedContent</span><span class="dl">'</span><span class="p">),</span>
<span class="na">_indicesForProperty</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">prop</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">content</span><span class="dl">'</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">item</span><span class="p">,</span> <span class="nx">index</span><span class="p">){</span>
<span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">prop</span><span class="p">)){</span> <span class="k">return</span> <span class="nx">index</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}).</span><span class="nx">compact</span><span class="p">();</span>
<span class="p">},</span>
<span class="na">userWins</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_hasWinningMove</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">userIndices</span><span class="dl">'</span><span class="p">));</span>
<span class="p">},</span>
<span class="na">computerWins</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_hasWinningMove</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">computerIndices</span><span class="dl">'</span><span class="p">));</span>
<span class="p">},</span>
<span class="na">_hasWinningMove</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">indices</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">lines</span><span class="dl">'</span><span class="p">).</span><span class="nx">some</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">match</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">EnumerableUtils</span><span class="p">.</span><span class="nx">intersection</span><span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">indices</span><span class="p">).</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="c1">//...</span>
<span class="p">});</span></code></pre></figure>
<p>Now let’s call <code class="language-plaintext highlighter-rouge">userWins</code> and <code class="language-plaintext highlighter-rouge">computerWins</code> every time a move is taken.</p>
<figure class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">App</span><span class="p">.</span><span class="nx">IndexController</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nx">ArrayController</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<span class="c1">//...</span>
<span class="na">selectBox</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">box</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">box</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">selected</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span>
<span class="nx">box</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">userSelected</span><span class="dl">'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">userWins</span><span class="p">())</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">_notify</span><span class="p">(</span><span class="dl">"</span><span class="s2">Congratulations. You beat a random number generator</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">unselectedContent</span><span class="dl">'</span><span class="p">).</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">_notify</span><span class="p">(</span><span class="dl">"</span><span class="s2">A draw? Is that the best you can do</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">performMove</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">performMove</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">available</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">unselectedContent</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">selected</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">selectMove</span><span class="p">();</span>
<span class="nx">available</span><span class="p">[</span><span class="nx">selected</span><span class="p">].</span><span class="kd">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">computerSelected</span><span class="dl">'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">computerWins</span><span class="p">())</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">_notify</span><span class="p">(</span><span class="dl">"</span><span class="s2">Ouch. You lost to a random number generator</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">_notify</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Ember</span><span class="p">.</span><span class="nx">run</span><span class="p">.</span><span class="nx">next</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
<span class="nx">alert</span><span class="p">(</span><span class="nx">msg</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="c1">//...</span>
<span class="p">})</span></code></pre></figure>
<p><a class="jsbin-embed" href="https://jsbin.com/ixomir/2/embed?live">Ember-Tic</a></p>
<h2 id="wrap-up">Wrap-up</h2>
<p>Now wasn’t that easy, if you read the final codebase, you’ll see I made a couple more tweaks.</p>
<ul>
<li>Adding a reset board button</li>
<li>Changing the wrapper div’s to anchor tags so it works on mobile</li>
</ul>
<p>Check out the final code and give it a go at <a href="http://bl.ocks.org/bradleypriest/6051289">http://bl.ocks.org/bradleypriest/6051289</a></p>
<p>The next step would be to make the UI a little smarter, I would probably check for any intersections that return two
matches and see if the missing index is still empty, but I’ll leave that as an exercise for the reader.</p>
<p>Have a great day, now go building something utterly useless and let me know <a href="https://twitter.com/bradleypriest">@bradleypriest</a></p>
<script src="//static.jsbin.com/js/embed.js">
</script>
Building Modern Web Apps: Framework is not a four letter word2012-12-01T00:00:00+00:00hhttps://www.bradleypriest.com/2012/12/01/building-modern-web-apps
<p>Here are the slides from my talk at <a href="jscamp.asia">jscamp.asia</a> about client-side MVC frameworks and EmberJS.</p>
<script async="1" class="speakerdeck-embed" data-id="e65ef5301d010130a7da1231381d6d46" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js">
</script>
What's new in EmberJS #192012-11-20T00:00:00+00:00hhttps://www.bradleypriest.com/2012/11/20/whats-new-in-emberjs-19
<p>###Weekly Wrapup #19</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li><a href="https://github.com/emberjs/ember.js/commit/ed38ab3777733597ac5abd33ce26c3edeb2d7d13">ed38ab</a> removes the deprecated defaulting of a view’s context to itself, this may break some code samples around the place, but should not affect full applications.</li>
</ul>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p>As of <a href="https://github.com/emberjs/ember.js/pull/1393">PR 1393</a>, <code class="language-plaintext highlighter-rouge">_super()</code> can now be called inside of computed properties.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1504">PR 1504</a> adds an example of how to render a <code class="language-plaintext highlighter-rouge">CollectionView</code> with different childViews.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1528">PR 1528</a> adds an <code class="language-plaintext highlighter-rouge">afterRender</code> queue for view rendering. A common use of this is to perform an action after all of a <code class="language-plaintext highlighter-rouge">CollectionView</code>’s children have been rendered.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/476">PR 476</a> provides some initial error handling to ember-data. A 422 puts the record into an invalid state and sets an <code class="language-plaintext highlighter-rouge">errors</code> object onto the model. Any other server failure puts the object into an error state.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/422">PR 422</a> reinstates the <code class="language-plaintext highlighter-rouge">RESTAdapter</code>’s default transforms.</p>
</li>
<li>
<p>A conscious effort is being made to be format agnostic and not hardcode any method names/fields to JSON in ember-data, see <a href="https://github.com/emberjs/data/commit/03739a7783de33b1ab1a89f3ecef236d7d3ba064">here</a>. This shouldn’t cause too many issues unless you are using a highly customized adapter.</p>
</li>
</ul>
<h4 id="resources">Resources</h4>
<ul>
<li>At the recent Ember meetup at <a href="https://addepar.com/">Addepar</a> <a href="https://addepar.com/ember/">Tom and Yehuda talked</a> about upcoming changes to the router and ember-data, worth a look.</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #182012-10-30T00:00:00+00:00hhttps://www.bradleypriest.com/2012/10/30/whats-new-in-emberjs-18
<p>Ember 1.0.0-pre.2 has been released, now with a semver compatible release number ;)</p>
<p>###Weekly Wrapup #18</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>
<p>Ember-Data revision 7 is out, which changes how relationship changes are acknowledged check out <a href="https://github.com/emberjs/data/blob/master/BREAKING_CHANGES.md">BREAKING_CHANGES</a> for details.</p>
</li>
<li>
<p>A (currently) private mixin, <code class="language-plaintext highlighter-rouge">DS.Mappable</code>, has been introduced to implement per-type adapters, see the <a href="https://github.com/emberjs/data/commit/2609b8f1b6195e2545f6485c7097512765478b4f">commit</a> and the <a href="https://github.com/emberjs/data/commit/ca0ab37fbe9d0afdc896c7a8410e27cafabfb203">documentation</a></p>
</li>
</ul>
<h4 id="updates">Updates</h4>
<ul>
<li>Ember 1.0.0-pre.2 released, check out the <a href="http://emberjs.com/blog/2012/10/25/ember-1-0-pre2/">blog post</a> and the <a href="https://github.com/emberjs/ember.js/blob/master/CHANGELOG">changelog</a></li>
</ul>
<h4 id="nb">N.B</h4>
<ul>
<li>Explicitly missing from this post is mention of the <a href="https://gist.github.com/3981133">new router API</a> being thrown around, I don’t mean to bring personal preferences in, but I believe this is heading in the wrong direction. Currently getting started with the <code class="language-plaintext highlighter-rouge">Ember.Router</code> can be a bit of a hassle but I personally believe learning the philosophy behind the router/state-manager is the most important step in understanding Ember. Luckily it looks like the old API <a href="https://twitter.com/tomdale/status/263317907596013568">won’t be going anywhere</a>.</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #172012-10-23T00:00:00+00:00hhttps://www.bradleypriest.com/2012/10/23/whats-new-in-emberjs-17
<p>It’s been a good week for Ember updates, big thanks to Peter Wagenet for single-handedly reviewing and cleaning up <a href="https://twitter.com/wagenet/status/259510421814398976">every single Ember ticket</a>.</p>
<p>###Weekly Wrapup #17</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>EmberJS now requires at least jQuery 1.7.2</li>
<li><a href="https://github.com/emberjs/ember.js/commit/710d1e1ab55a60edd259d8a3cd9c7467e1b50c41">ENV.VIEW_PRESERVES_CONTEXT</a> & <a href="https://github.com/emberjs/ember.js/commit/5ef55f22c584abc788fd98994af591f010ba82e9">ENV.CP_DEFAULT_CACHEABLE</a> flags have been removed.</li>
</ul>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1459">PR #1406</a> changes the Ember.Deferred mixin to be Promises/A compatible by using RSVP.js.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1465">PR #1465</a> adds support for globbed routes in the router.</p>
</li>
<li>
<p>EmberJS now has a <a href="https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a> page. If you’ve ever felt like you’ve found a bug or wanted to know better how to help out, there’s plenty of info there.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/f103fe49de72c88c6c746e74ab0a500b51d35473">f103fe</a> deprecates using {{collection}} without a class in favor of {{each}}.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/249">PR #249</a> gives ember-data the ability to set a custom URL, just make sure you set up CORS properly.</p>
</li>
</ul>
<h4 id="articles">Articles</h4>
<ul>
<li>
<p>A new official guide has been added <a href="http://emberjs.com/guides/router_primer/">Building Applications with Ember.js</a></p>
</li>
<li>
<p>James Croft runs through building a <code class="language-plaintext highlighter-rouge">FilterableMixin</code> for <code class="language-plaintext highlighter-rouge">Ember.ArrayProxy</code> <a href="http://matchingnotes.com/ember-array-proxy/filterable-mixin">here</a>.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #162012-10-15T00:00:00+00:00hhttps://www.bradleypriest.com/2012/10/15/whats-new-in-emberjs-16
<p>Sorry guys and gals, it’s been a couple of weeks since I last posted, been busy beta launching my new startup <a href="http://tradegecko.com">TradeGecko</a>, now back to the scheduled programming.</p>
<p>Lot’s of big changes merged in the last few days, most newsworthy is the <code class="language-plaintext highlighter-rouge">relationships-improvements</code> branch of ember-data has been merged.</p>
<p>###Weekly Wrapup #16</p>
<h4 id="relationship-improvements">Relationship Improvements</h4>
<ul>
<li>
<p>The <code class="language-plaintext highlighter-rouge">relationships-improvements</code> branch of ember-data has been merged, this brings quite a few breakages along, particularly if you are modifying the defaults in any way.</p>
</li>
<li>
<p>There’s a lot to see here, so I suggest you take a look at the new documentation. I’ll try and put together a migrating to ember-data V5 blog post in the next couple of weeks once I finish migrating my apps.</p>
</li>
<li>
<p>If you have any outstanding issues PR’s against ember-data please take the time to check they’re still relevant and update them against the latest changes.</p>
</li>
</ul>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1406">PR #1406</a> gives us an Ember.Deferred mixin which (almost, still WIP) implements the Promises/A spec.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1354/">PR #1354</a> adds support for passing multiple contexts to events.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/305202fa51aca55ce1ff935aa9fb8ebe3da4a0d4">305202</a> removes the dependency on the browser <code class="language-plaintext highlighter-rouge">window</code>, this should make it easier for people using Ember with technologies like CommonJS and AMD. Check out the commit for details.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1198">PR #1198</a> adds <code class="language-plaintext highlighter-rouge">presentCurrentView</code>, <code class="language-plaintext highlighter-rouge">dismissCurrentView</code>, <code class="language-plaintext highlighter-rouge">appendCurrentView</code> and <code class="language-plaintext highlighter-rouge">removeCurrentView</code> to Ember.ContainerView (and consequently outlets) for handling animations and so forth.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1425">PR #1425</a> fixes an error with popstate on Chrome</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/945cd4a5a4f0851d9729385225ecd356f7f05ca5">945cd4</a> no longer throws an error for Ember Apps without a router</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/134fc61b764ef5b464ab3ebef968716b7df5c50c">134fc6</a> Ember now includes a basic instrumentation API.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1449">PR #1449</a> allows toggling extending prototypes by object type.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/410">PR #410</a> on ember-data changes the semantics of <code class="language-plaintext highlighter-rouge">findAll()</code> and adds an <code class="language-plaintext highlighter-rouge">all()</code> method which pretty much implements the old way.</p>
</li>
</ul>
<h4 id="articles">Articles</h4>
<ul>
<li>ghempton <a href="http://codebrief.com/2012/10/ember-dot-js-analytics-integration/">explains how he integrates Analytics with Ember</a>.</li>
<li>tomdale giving a <a href="http://www.youtube.com/watch?v=djhAsWGOImk">talk on ember-data</a> at last weeks Prague.js.</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #152012-09-24T00:00:00+00:00hhttps://www.bradleypriest.com/2012/09/24/whats-new-in-emberjs-15
<p>There’s a new documentation site up at <a href="http://emberjs.com/api/">http://emberjs.com/api/</a>. All of the documentation has been converted to YUIDoc for this move, so if you notice anything strange please send in a fix.</p>
<p>###Weekly Wrapup #15</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/bb149dcbb7df91866fce10e6dbec78c3e439d0ee">bb149d</a> Removes support for inline anonymous templates</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/1c7cf46a866a545f68192ab588ee93a1ea160e00">1c7cf46</a> Adds the <code class="language-plaintext highlighter-rouge">autoinit</code> flag to Application, no need to call <code class="language-plaintext highlighter-rouge">App.initialize</code> anymore unless you are doing something obscure.</p>
</li>
</ul>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p>Handlebars 1.0-rc.1 has now been released.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1310">PR 1310</a> The {{each}} helper now supports an <code class="language-plaintext highlighter-rouge">itemViewClass</code> for blockless use.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1340/files">PR 1340</a> Injections can be specified the order to run before/after others.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/1317">PR 1317</a> The application initialization process has been refactored.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #142012-09-10T00:00:00+00:00hhttps://www.bradleypriest.com/2012/09/10/whats-new-in-emberjs-14
<p>Been a bit quiet on github these last couple of weeks, I guess everyone’s got to do some real work sometimes. Still plenty of bug fixes and features being put together by the rest of the community though, which is good to see</p>
<p>###Weekly Wrapup #14</p>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/9ecb57019f0ba705bcc67aa59d01a3816e7bbfa4">9ecb570</a> adds <code class="language-plaintext highlighter-rouge">currentPath</code> to <code class="language-plaintext highlighter-rouge">Ember.StateManager</code> and therefore the router as shorthand for calling <code class="language-plaintext highlighter-rouge">currentState.path</code></p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/issues/1330">PR 1330</a> cleans up some issues with Ember.onerror in some browsers.</p>
</li>
<li>
<p>Lots of documentation <a href="https://github.com/emberjs/ember.js/commit/bad53798ac5e3efad2069beeae0248c5fcf99ebc">has</a> <a href="https://github.com/emberjs/ember.js/commit/479e598eaea64f6714b8a4619e8cb5ca87ccc6a5">been</a> <a href="https://github.com/emberjs/ember.js/commit/430c2b6960168b349e0e13a70145638e0eeea403">added</a> to the core <code class="language-plaintext highlighter-rouge">Ember.Application</code> which should hopefully start to clear the basics up.</p>
</li>
</ul>
<h4 id="articles">Articles</h4>
<ul>
<li>
<p>trek has put together what is probably the best <a href="http://trek.github.com">Intro to EmberJS</a> article I’ve seen. It’s worth a read even if you’re an Ember pro.</p>
</li>
<li>
<p><a href="http://techblog.fundinggates.com/blog/2012/08/ember-handlebars-helpers-bound-and-unbound/">Ember Handlebars Helpers, Bound and Unbound</a> from joliss.<br />
I personally had been using <a href="https://gist.github.com/3362086">this gist</a> up until now, but this looks like a cleaner alternative until <a href="https://github.com/emberjs/ember.js/pull/1274">PR 1274</a> gets merged.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #132012-08-27T00:00:00+00:00hhttps://www.bradleypriest.com/2012/08/27/whats-new-in-emberjs-13
<p>Most of the work at the moment seems to be in the refactoring of ember-data. It’s not in master yet, but expect some pretty big changes. There’s also a lot of work going on in the documentation side, if you find something amiss please help the core team out.</p>
<p>###Weekly Wrapup #13</p>
<h4 id="breaking-changes">Breaking changes</h4>
<ul>
<li><a href="https://github.com/emberjs/ember.js/commit/ba3e74e02d160fa870181a851c9e897fc66e4b6c">ba3e74</a> updated the application set up process, this should be seamless for most people, but make sure your app is calling <code class="language-plaintext highlighter-rouge">initialize</code>.</li>
</ul>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/933b2b4a6eb4f82884c4ec5c567890ffb458beab">933b2b</a> adds a <code class="language-plaintext highlighter-rouge">disconnectOutlet</code> method. AFAICT this is only useful for very specific usecases as Ember handles normal view management for you.</p>
</li>
<li>
<p>The awesome ember-bootstrap project has moved. You can find it at it’s new home at <a href="https://github.com/emberjs-addons/ember-bootstrap">https://github.com/emberjs-addons/ember-bootstrap</a></p>
</li>
</ul>
<h4 id="articles">Articles</h4>
<p>There’s a great article on the current state of routing over on <a href="http://www.thesoftwaresimpleton.com/blog/2012/08/20/routing_update/">dagda1’s blog</a></p>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #122012-08-07T00:00:00+00:00hhttps://www.bradleypriest.com/2012/08/07/whats-new-in-emberjs-12
<p>Big News: Last week saw the release of Ember 1.0.pre, check out the <a href="http://emberjs.com/blog/2012/08/03/ember-1-0-prerelease/">release post</a> and download your copy <a href="https://github.com/downloads/emberjs/ember.js/ember-1.0.pre.js">here</a>.</p>
<p>This is a huge step forward, no longer do you have to toss up whether to recommend the defunct 0.9.8 or wildly changing bleeding edge when introducing ALL of your friends to Ember.</p>
<p>N.B. There was a small bug with the 1.0.pre release which has since been <a href="https://github.com/emberjs/ember.js/commit/f1ec52aaa0713c7edeca237d38f172e0671a4c0e">fixed</a>.</p>
<p>###Weekly Wrapup #12</p>
<h4 id="updates">Updates</h4>
<ul>
<li>
<p><a href="http://docs.emberjs.com/">http://docs.emberjs.com/</a> has been updated to 1.0.pre documentation, no more building your own local copy. <s>There is also work being done currently to get an edge docs site up, you can find a copy at [http://ember-edge-docs.herokuapp.com](http://ember-edge-docs.herokuapp.com/) whilst they sort out a proper domain.</s> Edge docs site now live: <a href="http://docs.edge.emberjs.com/">http://docs.edge.emberjs.com</a></p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember-rails">ember-rails</a> and the <a href="https://github.com/emberjs/starter-kit">starter-kit</a> have been updated to 1.0.pre hopefully this should fix a lot of issues with getting started with ember.</p>
</li>
<li>
<p>For all you pythonistas out there, there is now a <a href="http://pypi.python.org/pypi/django-ember/0.1">django-ember</a> package available.</p>
</li>
</ul>
<p>Sorry, not too many code updates this week, but if you really want to get your hands dirty, check out the <a href="https://github.com/emberjs/data/tree/relationship-improvements">relationship-improvements</a> WIP branch of ember-data.</p>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #112012-07-24T00:00:00+00:00hhttps://www.bradleypriest.com/2012/07/24/whats-new-in-emberjs-11
<p>Some pretty big breaking changes again this week, part of being on the edge though, right.</p>
<p>###Weekly Wrapup #11</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>
<p>In the <a href="https://github.com/emberjs/ember.js/pull/1176">biggest change</a> of the week, <code class="language-plaintext highlighter-rouge">getPath/setPath</code> have been removed in favour of supporting full paths in <code class="language-plaintext highlighter-rouge">get</code> and <code class="language-plaintext highlighter-rouge">set</code>.</p>
</li>
<li>
<p>As of <a href="https://github.com/emberjs/ember.js/commit/83b7a61a892e55423cf1e66f606b13435bcab8f0">83b7a6</a> the <code class="language-plaintext highlighter-rouge">action</code> helper now requires an explicit context to be set. The api has also changed, the context is now simply passed as an optional second parameter. {{action edit context=”post”}} becomes {{action edit post}}. If you were relying on default contexts you will need to use {{action edit this}}</p>
</li>
</ul>
<h4 id="improvements">Improvements</h4>
<ul>
<li>
<p>PR <a href="https://github.com/emberjs/ember.js/pull/1044/">1044</a> added <code class="language-plaintext highlighter-rouge">canInvoke</code> and <code class="language-plaintext highlighter-rouge">tryInvoke</code> methods to check and perform methods only if the target responds to them.</p>
</li>
<li>
<p>PR <a href="https://github.com/emberjs/ember.js/pull/732">732</a> adds the ability to provide a falsy option to Ember.View bindings. e.g. <code class="language-plaintext highlighter-rouge">classNameBindings: ['isEnabled:enabled:disabled']</code></p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/396c08b1322f4b642a65005cc89cdd7bb8acce06">396c08</a> adds the new <code class="language-plaintext highlighter-rouge">connectControllers</code> method to make other controllers available on the controller currently being used. <code class="language-plaintext highlighter-rouge">overviewController.connectControllers('person', 'post');</code> will let you do <code class="language-plaintext highlighter-rouge">controller.get('postController')</code> on the overviewController.</p>
</li>
</ul>
<p>If anyone has worked out how to use jekyll syntax highlighting with handlebars brackets, please get in touch.</p>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #102012-07-16T00:00:00+00:00hhttps://www.bradleypriest.com/2012/07/16/whats-new-in-emberjs-10
<p>Sorry I missed last week, but literally nothing had happened.
This week, there have been some massive changes under the hood.</p>
<p>###Weekly Wrapup #10</p>
<h4 id="improvements">Improvements</h4>
<ul>
<li>
<p>The <a href="https://github.com/emberjs/ember.js/tree/simplify-properties">simplify-properties</a> branch was merged into master, this brings some sorely needed readability for us commonfolk for how the inner workings of property handling works.</p>
</li>
<li>
<p>ember-data has a vastly improved <a href="https://github.com/emberjs/data/commit/0e81ecfc071a9e1703ad7ad3de00aca66265b4b7">FixtureAdapter</a></p>
</li>
<li>
<p>A new <code class="language-plaintext highlighter-rouge">recordIsLoaded</code> method was added to data in <a href="https://github.com/emberjs/data/commit/b63b84b07d203e4467df034a1c19c37de20648a2">b63b84</a></p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">connectOutlet</code> has been given <a href="https://github.com/emberjs/ember.js/commit/809746b05cc7fc3c278596a60dfbcb3e8b384348">another syntax</a> (outletName, name, context) to make it easier to use custom outlet names. As always the options hash is still available if you need to use custom combinations.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/d77a0cf69de505104290874fedc1224b8a77b53c">d77a0c</a> adds the option to add a non standard <code class="language-plaintext highlighter-rouge">rootUrl</code> to the router.</p>
</li>
<li>
<p><a href="https://github.com/wagenet/ember.js/commit/e668276a3aab382e145c3bc7afd059a9a6438534">e66827</a> meta clicks are now properly respected.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments, twitter or IRC at #emberjs.</p>
What's new in EmberJS #92012-07-02T00:00:00+00:00hhttps://www.bradleypriest.com/2012/07/02/whats-new-in-emberjs-9
<p>Pretty quiet this week sorry</p>
<p>###Weekly Wrapup #9</p>
<h4 id="improvements">Improvements</h4>
<ul>
<li>
<p>ember-data <a href="https://github.com/emberjs/data/commit/3847ed317714556b834198bce60aefbd31fa83e3">now</a> no longer sets the <code class="language-plaintext highlighter-rouge">isDirty</code> flag if the value hasn’t changed.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/9d82473d7a543ea2e2b7b6d24dc2486aff7703c1">9d8247</a> fixes the router to always call <code class="language-plaintext highlighter-rouge">connectOutlets</code> of intermediate routes when using the router.</p>
</li>
<li>
<p>The router has also had a couple more tweaks to handle initialStates better.</p>
</li>
</ul>
<h4 id="articles">Articles</h4>
<ul>
<li>ghempton has a redux of an old post on layout and routing <a href="http://codebrief.com/2012/07/anatomy-of-an-ember-dot-js-app-part-i-redux-routing-and-outlets">http://codebrief.com/2012/07/anatomy-of-an-ember-dot-js-app-part-i-redux-routing-and-outlets</a></li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS #82012-06-25T00:00:00+00:00hhttps://www.bradleypriest.com/2012/06/25/whats-new-in-emberjs-june-25
<p>Not so much new code this week, but the documentation is making leaps and bounds</p>
<p>###Weekly Wrapup #8</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li><a href="https://github.com/emberjs/ember.js/commit/d23ea3ab501fc0e8f591a793b927f572436647a1">d23ea3</a> changes <code class="language-plaintext highlighter-rouge">app.stateManager</code> to <code class="language-plaintext highlighter-rouge">app.router</code></li>
</ul>
<h4 id="improvements">Improvements</h4>
<ul>
<li>
<p>One of the last major bugs in the new router has a <a href="https://github.com/emberjs/ember.js/pull/1059">PR</a> for a fix.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/commit/37d3319360be4e8f242a39111290a844720af3ab">37d331</a> ember-data now gives the store to each controller.</p>
</li>
<li>
<p>In ember-data the ManyArray now provides a <code class="language-plaintext highlighter-rouge">isLoaded</code> flag <a href="https://github.com/emberjs/data/commit/f707b6c4868e589c355ad25f1c0d54914f916e72">f707b6c</a></p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS June 182012-06-18T00:00:00+00:00hhttps://www.bradleypriest.com/2012/06/18/whats-new-in-emberjs-june-18
<p>A couple of breaking changes this week, if you’ve been following master, there’s a couple of quick tweaks that need to be made.</p>
<p>###Weekly Wrapup #7</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/d8383b65aaf9dcd0f92687b7ed6921f1a436a73c">d8383b</a> creates an <code class="language-plaintext highlighter-rouge">Ember.Route</code> subclass of <code class="language-plaintext highlighter-rouge">Ember.State</code>, if you’re using the new router, make sure you change over as there are currently no warnings.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/be69395f5eec4187b1df052d7386bcda45f79475">be6939</a> changes the arguments expected by <code class="language-plaintext highlighter-rouge">connectOutlet</code>. Check out the commit comment for details, but the basic change is that <code class="language-plaintext highlighter-rouge">connectOutlet</code> now takes a single string to define the View and Controller, removing the magic. If you need to customize further it can also take a hash of name, outletName, viewClass, controller and context.</p>
</li>
<li>
<p>The {{action}} helper got some big changes. It now calls <a href="https://github.com/emberjs/ember.js/commit/aaa22a7ced26ec4cc079818b6a8991baed51d77a">stopPropagation</a> and <a href="https://github.com/emberjs/ember.js/commit/4b7b13f6f594a32b5abdc7419d22478f5f549328">preventDefault</a> automatically.</p>
</li>
</ul>
<h4 id="improvements">Improvements</h4>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/2d26a36f4119ffa0f8b41157dbb2856f27a33420">2d26a36</a> adds naïve route sorting. This fixes a <a href="https://github.com/emberjs/ember.js/pull/969">situation</a> where a <code class="language-plaintext highlighter-rouge">:post_id</code> would always take precedence over a <code class="language-plaintext highlighter-rouge">new</code> segment. Now it sorts based on substrings, segment length and dynamicism.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">Ember.Evented</code> now has <a href="https://github.com/emberjs/ember.js/commit/1809e65012b93c0a530bfcb95eec22d972069745">one</a> method to add a one-time eventListener.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">Ember.Evented</code> uses <code class="language-plaintext highlighter-rouge">trigger</code> instead of <code class="language-plaintext highlighter-rouge">fire</code> to keep in line with jQuery.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS June 112012-06-12T00:00:00+00:00hhttps://www.bradleypriest.com/2012/06/12/whats-new-in-emberjs-june-12
<p>A couple of new guides out this week and still plenty of docfixes and tidying up going on. I urge everyone to have read through the Ember source sometime if you haven’t already.</p>
<p>###Weekly Wrapup #6</p>
<ul>
<li>
<p>Two new official guides have been released on <a href="http://emberjs.com/guides/outlets/">application structure/outlets</a> and <a href="http://emberjs.com/guides/asynchrony/">asynchrony</a>. Check them out they’re great for newbies and not-so-newbies alike.</p>
</li>
<li>
<p>A new <a href="https://github.com/emberjs/ember.js/blob/master/packages/ember-runtime/lib/mixins/sortable.js">Ember.Sortable</a> mixin has been added and is mixed in to ArrayProxy by default. To use add a <code class="language-plaintext highlighter-rouge">sortProperties</code> value to the Array and use <code class="language-plaintext highlighter-rouge">arrangedContent</code> to get the sorted values.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/pull/945">pushState</a> and <a href="https://github.com/emberjs/ember.js/pull/935">none</a> locations have been added to the router to complement the existing hash implementation.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/871042a0d7083c9f5c5b6258fb0a84af814c34dd">871042</a> moves dom events to use Ember’s internal event system. This has the side-effect that returning false from a method should now stop propagation.</p>
</li>
<li>
<p>A couple of IE related bugs were squashed</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS June 52012-06-05T00:00:00+00:00hhttps://www.bradleypriest.com/2012/06/05/whats-new-in-emberjs-june-5
<p>Again mostly routing stuff this week, although it’s great to see a lot of work being done on documentation.</p>
<p>###Weekly Wrapup #5</p>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember-rails/commit/82d35eb582d4a0a73613bba61b92613484a03a62">82d35e</a>The ember-rails gem now generates the relevant ember resources when <code class="language-plaintext highlighter-rouge">rails g resource</code> is run</p>
</li>
<li>
<p>Removed deprecated use of <a href="https://github.com/emberjs/ember.js/commit/50d66622e551d0b98dcce80d12a9a8cd0541a873">wildcards *</a> and <a href="https://github.com/emberjs/ember.js/commit/bf9400510f00a2962bb36162eae642c56731a34a">leading periods</a> in paths.</p>
</li>
<li>
<p>As of <a href="https://github.com/emberjs/ember.js/commit/ee46ed0a3bbde4f1b21e5b7d4a5550470a138a4e">ee46ed</a>, views now inherit controllers from their parents.</p>
</li>
<li>
<p>In one of the more controversial changes to Ember as of late, <a href="https://github.com/emberjs/ember.js/commit/7ae011753e595086287f06733028b260e0526847">7ae011</a> removes binding transforms. Check out the comments for the recommended replacement.</p>
</li>
<li>
<p>As of <a href="https://github.com/emberjs/ember.js/commit/7ff23ee362b142f301b595e439afa964f3895b7c">7ff23e</a> routes should be handled better when using the back/forward buttons in the browser.</p>
</li>
<li>
<p>A heroku app is now generating and uploading a new version of ember-latest after every push. You can now always get the latest version <a href="https://github.com/emberjs/ember.js/downloads">here</a>.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS May 292012-05-29T00:00:00+00:00hhttps://www.bradleypriest.com/2012/05/29/whats-new-in-emberjs-may-29
<p>Lots and lots of work on the master branch this week to do with routing. It’s getting better every day</p>
<p>###Weekly Wrapup #4</p>
<ul>
<li>
<p>As of <a href="https://github.com/emberjs/ember.js/commit/d1fd4ec850b0b32f21a51068a56c318478bf6632">d1fd4e</a> Handlebars is not bundled with Ember, if you’re not already using it in your application you’ll be told about it. And if you’re using rails the ember-rails gem includes it for you anyway.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/10f7ab46a7cc553d4e120693b2b26acd8be73fa5">10f7ab</a> introduces Ember.ObjectProxy and some Ember.ObjectController sugar</p>
</li>
<li>
<p>Routing changes include adding <a href="https://github.com/emberjs/ember.js/commit/91a8975b8d3a0b873b421f1dbc4ea41f92c92bc2">redirectsTo</a></p>
</li>
<li>
<p>The router now initializes at a <a href="https://github.com/emberjs/ember.js/commit/7b15026577f1efee02f2a90e2f560094b2d508c7">root state</a>.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">goToState</code> has been replaced by <code class="language-plaintext highlighter-rouge">transitionTo</code> in statemanagers</p>
</li>
<li>
<p>setupContext/setupControllers has been renamed <code class="language-plaintext highlighter-rouge">connectOutlets</code></p>
</li>
<li>
<p>The {{outlet}} helper has been added. Check out <a href="https://github.com/emberjs/ember.js/blob/master/packages/ember-handlebars/lib/helpers/outlet.js">this file</a> for details. This gives the ability for a controller to fill in the currentView for a given area.</p>
</li>
<li>
<p>In <a href="https://github.com/emberjs/data/pull/268">PR #268</a> a new Errors object has been proposed for ember-data, designed to plug and play with Rails</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS May 212012-05-21T00:00:00+00:00hhttps://www.bradleypriest.com/2012/05/21/whats-new-in-emberjs-may-21
<p>EmberJS 0.9.8 just released with a shiny new website. Check it out <a href="http://emberjs.com">http://emberjs.com</a>.</p>
<p>###Weekly Wrapup #3</p>
<ul>
<li>
<p>EmberJS 0.9.8 just released, check out the <a href="https://github.com/emberjs/ember.js/blob/master/CHANGELOG">changelog</a>.</p>
</li>
<li>
<p>Most importantly routing is now built right in to core, check out a couple of blog posts about it <a href="https://gist.github.com/2679013">here</a>, <a href="http://tomdale.net/2012/05/ember-routing/">here</a> and <a href="https://gist.github.com/2728699">here</a>. Beware it’s not 100% finished, but its pretty close.</p>
</li>
<li>
<p>Bindings being cacheable by default and views reserving context are now on by default. If you’re not ready to change yet, set ENV.CP_DEFAULT_CACHEABLE = false or ENV.VIEW_PRESERVES_CONTEXT = false to change them back, but beware the option is being removed with the 1.1 release.</p>
</li>
<li>
<p>The handlebars <a href="https://github.com/emberjs/ember.js/commit/cdfb4673c80c17203f940f9c2087661a9116880a">action</a> helper now takes a context argument to pass instead of the jQuery event.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS May 142012-05-14T00:00:00+00:00hhttps://www.bradleypriest.com/2012/05/14/whats-new-in-emberjs-may-14
<p>Not too many changes to master this week, but looks like baked-in routing might be just around the corner.</p>
<p>###Weekly Wrapup #2</p>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commits/routing">Routing</a>: There’s been a bit of action on the routing branch in the last few days, and it’s looking really good, check out a description from wycats <a href="https://gist.github.com/2679013">here</a>.</p>
</li>
<li>
<p>There’s a bit of a discussion going on <a href="https://github.com/emberjs/ember.js/pull/803">here</a> on implementing a SortedArrayProxy into core.</p>
</li>
<li>
<p>ghempton’s <a href="https://github.com/ghempton/ember-routemanager">route-manager</a> got some cleaning up, it now generates hashbang URLs when pushState is off and has fixed the initial page load render bug.</p>
</li>
<li>
<p>Ember data has a couple of <a href="https://github.com/emberjs/data/pull/253">pull</a> <a href="https://github.com/emberjs/data/pull/252">requests</a> fixing a couple of bugs with parent-child relationships. With these changes creating a parent and it’s children in one transaction doesn’t lose the children.</p>
</li>
</ul>
<p>If I missed anything please let me know in the comments or on twitter.</p>
What's new in EmberJS May 72012-05-07T00:00:00+00:00hhttps://www.bradleypriest.com/2012/05/07/whats-new-in-emberjs-may-7
<p>I am a huge Ember supporter. I have only been using the framework for 4 weeks now, but I am a complete convert. Hell, I’m building my new <a href="http://tradegecko.com">startup</a> in it.</p>
<p>I don’t have any cool libraries to share for it just yet, but in the meantime this is the least I can do.</p>
<p>###Weekly Wrapup #1</p>
<ul>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/00b8940af1c948dd1974be184e022269a87a461d">#00b894</a> updates ContainerView to optionally take a currentView object, which sets a single view inside the continer, great for statemanagers. (I currently use ember-layout, this commit may make that obsolete?)</p>
</li>
<li>
<p><a href="https://github.com/emberjs/ember.js/commit/f9681830b7385d2c85722c21409ae7c33da7dbee">#f96818</a> Make it easy to inject controllers. I’m gonna be honest, I don’t actually understand what’s happening here, but it looks like they’re working on some big updates.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">each foo in bar</code> and <code class="language-plaintext highlighter-rouge">with foo as bar</code> handlebars helpers were added.</p>
</li>
<li>
<p>A <a href="https://github.com/emberjs/ember.js/commit/09d7ad62b214c094621ade5515d2a29a59464f89">whole</a> <a href="https://github.com/emberjs/ember.js/commit/fb0848b2d22e7325f59f89507cd4e855bdad9255">lot</a> of <a href="https://github.com/emberjs/ember.js/commit/7e839f0fc32371c8776fc6da900a30a3e6906aa1">refactoring</a> has been done to mutable array and enumerable to help speed things up.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/229">PR #229</a> added the ability to rollback transactions to ember-data, both automatically and manually via <code class="language-plaintext highlighter-rouge">person.get('transaction').rollback()</code>.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/230">PR #230</a> makes it easier to create child records e.g. <code class="language-plaintext highlighter-rouge">blog.get('posts').createRecord()</code>.</p>
</li>
<li>
<p><a href="https://github.com/emberjs/data/pull/236">PR #236</a> fixes lifecycle events and makes <code class="language-plaintext highlighter-rouge">didCreate</code> and <code class="language-plaintext highlighter-rouge">didUpdate</code> fire correctly.</p>
</li>
</ul>
<p>If I missed anything big please let me know in the comments or on twitter.</p>
<p>P.S. Thanks to <a href="http://afreshcup.com/home/category/edge-rails">Mike Gunderloy</a> for the idea.</p>
Just (f**king) do it2012-03-27T00:00:00+00:00hhttps://www.bradleypriest.com/2012/03/27/just-fking-do-it
<p>It’s a bit of a cliché these days, but it still makes a helluva lot of sense. <strong>Just (f**king) do it.</strong></p>
<p>I’ve been living in Auckland for a few years now, have a comfortable job at a respectable company, a great group of friends.
Some people would say I’m pretty settled, I personally would use the word complacent.</p>
<p>So when a few weeks ago the opportunity came to throw myself way out of my comfort zone, I was all for it. <strong>Just (f**king) do it.</strong></p>
<p>So, as of Friday I quit my job, gave notice on my apartment and am on my way to Singapore to work on <a href="http://tradegecko.com">TradeGecko</a> an exciting new startup with my brother Cameron and his business partner Carl.</p>
<p>I’m sure you’ll hear more about it from me over the coming few months, we’ve got 40 days left in the <a href="http://jfdi.asia">JFDI</a> incubator and quite a prototype to put together. I am so excited right now.</p>
<p>If you’re not completely happy with where you’re at or there’s something else you’re considering. <strong>Just (f**king) do it.</strong> You only have one life. Make the most of it.</p>
Hacking the Foursquare API for fun and profit??2012-03-26T00:00:00+00:00hhttps://www.bradleypriest.com/2012/03/26/hacking-the-foursquare-api-for-fun-and-profit
<p>So I have a housemate who has a certain fascination with burgers. His favourite ones seem to come from the local BurgerFuel.</p>
<p>For 12 months he was the Foursquare mayor of Burgerfuel Parnel, eating lunch their every second day (healthy right!!). Luckily they had a great two for one deal for the mayor so he always had half price burgers.</p>
<p>However, after a 4 month OE surprisingly he was ousted. Now that he’s back and into his habits again, it seems he just can’t quite get the mayorship back.</p>
<p>So I thought I’d give him a bit of help.</p>
<p>Here’s a quick little ruby script I wrote, use at your own risk, I can almost guarantee it’s against their ToS.</p>
<script src="https://gist.github.com/2204036.js?file=foursquare_bot.rb"> </script>
<p>Firstly log in to Foursquare and head to <a href="https://foursquare.com/oauth/">https://foursquare.com/oauth/</a> to register a new consumer.
You can fill in anything for the website and url, make sure to record the callback url though.</p>
<p>Open your console by running <code class="language-plaintext highlighter-rouge">irb -r ./foursquare_bot.rb</code></p>
<p>Run <code class="language-plaintext highlighter-rouge">FoursquareBot.get_oauth(client_id, callback_url)</code> to get a url to visit.
Authenticate with Foursquare and we’re good to go, just copy down the code parameter from the url you get redirected to.</p>
<p><img src="https://img.skitch.com/20120326-qia79s888pn5sdp8skn3trpqar.jpg" alt="URL" /></p>
<p>Now you can checkin whenever you like with this one liner.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"> <span class="no">Foursquare</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">insert_client_id</span><span class="p">).</span><span class="nf">checkin</span><span class="p">(</span><span class="n">your_location_id</span><span class="p">)</span></code></pre></figure>
<p>Next step is to make it a daemon and we’re ready to go.</p>
Accessing attributes from has_many :through join models2012-03-18T00:00:00+00:00hhttps://www.bradleypriest.com/2012/03/18/accessing-attributes-from-has-many-through-join-models
<p>I’ve been trying to help out a bit in the Rails section on <a href="http://stackoverflow.com">Stack Overflow</a> lately and have noticed a question that has come <a href="http://stackoverflow.com/questions/9355458/nested-has-many-through-attributes">up</a> <a href="http://stackoverflow.com/questions/9290100/making-activerecord-join-model-attributes-available-in-query-results">several</a> <a href="http://stackoverflow.com/questions/8874702/need-data-from-rails-join-table-has-many-through">times</a> lately.</p>
<p>Accessing an attribute from the join model on a has_many :through relationship. For the basics, check out the <a href="http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association">Rails guide</a> on the subject.</p>
<p>Here’s a pretty standard application of this in my awesome Library SAAS app:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Reader</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">has_many</span> <span class="ss">:book_loans</span>
<span class="n">has_many</span> <span class="ss">:books</span><span class="p">,</span> <span class="ss">:through</span> <span class="o">=></span> <span class="ss">:book_loans</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Book</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">has_many</span> <span class="ss">:book_loans</span>
<span class="n">has_many</span> <span class="ss">:readers</span><span class="p">,</span> <span class="ss">:through</span> <span class="o">=></span> <span class="ss">:book_loans</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">BookLoan</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">belongs_to</span> <span class="ss">:book</span>
<span class="n">belongs_to</span> <span class="ss">:reader</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">BookController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">show</span>
<span class="vi">@book</span> <span class="o">=</span> <span class="no">Book</span><span class="p">.</span><span class="nf">includes</span><span class="p">(</span><span class="ss">:readers</span><span class="p">).</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p>And on the books#show page we want to show all the people who have checked out a particular book.</p>
<figure class="highlight"><pre><code class="language-erb" data-lang="erb"> <span class="cp"><%=</span> <span class="vi">@book</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span>
Readers:
<span class="nt"><ul></span>
<span class="cp"><%</span> <span class="vi">@book</span><span class="p">.</span><span class="nf">readers</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">reader</span><span class="o">|</span> <span class="cp">%></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">reader</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="nt"></ul></span></code></pre></figure>
<p>Now what if I want to add the librarian who checked out the book to them to the page. This is stored as the <code class="language-plaintext highlighter-rouge">librarian</code> column on the BookLoan model, which we don’t actually have access to in the view at the moment.</p>
<p>This is my current solution to the problem, it involves a bit of SQL which might be a little scary for beginners, please leave a comment if you’ve got a better idea, I may even look into seeing if it’s achievable with ARel sometime soon.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"> <span class="k">class</span> <span class="nc">Book</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">has_many</span> <span class="ss">:readers</span><span class="p">,</span> <span class="ss">:through</span> <span class="o">=></span> <span class="ss">:book_loans</span><span class="p">,</span>
<span class="ss">:select</span> <span class="o">=></span> <span class="s2">"readers.*, book_loans.book_loan_librarian AS book_loan_librarian"</span>
<span class="k">end</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-erb" data-lang="erb"> <span class="cp"><%</span> <span class="vi">@book</span><span class="p">.</span><span class="nf">readers</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">reader</span><span class="o">|</span> <span class="cp">%></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">reader</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span> by <span class="cp"><%=</span> <span class="n">reader</span><span class="p">.</span><span class="nf">book_loan_librarian</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span></code></pre></figure>
<p>If anyone has any questions/suggestions feel free to leave a comment or hit me up on Twitter.</p>
<p><strong>N.B.</strong> I was originally going to use <code class="language-plaintext highlighter-rouge">book_loan.created_at</code> but ActiveRecord doesn’t automatically typecast the extra columns returned which would be a bit out of the scope of this post.</p>
<p>EDIT: In Rails 4+ it would look like this</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"> <span class="n">has_many</span> <span class="ss">:readers</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span> <span class="nb">select</span><span class="p">(</span><span class="s2">"readers.*, book_loans.book_loan_librarian AS book_loan_librarian"</span><span class="p">)</span> <span class="p">},</span>
<span class="ss">:through</span> <span class="o">=></span> <span class="ss">:book_loans</span></code></pre></figure>
TIL The very, very long way2011-09-19T00:00:00+00:00hhttps://www.bradleypriest.com/2011/09/19/til-the-very-very-long-way
<p>Whilst upgrading an application to Rails 3.1 recently I ran into one annoying heisenberg.</p>
<p>Long story short, do not use “stream” as a controller action name in 3.1 as it is used by the new HTTP streaming.</p>
ActiveRecord Ranges2011-06-18T00:00:00+00:00hhttps://www.bradleypriest.com/2011/06/18/activerecord-ranges
<p>Just a quick one today, I’m going to mention a quick trick you may have heard about, but is definitely worth knowing.</p>
<p>When using ActiveRecord as well as passing a String/Integer or Array into a query you can also use a Range.</p>
<p>I find this particularly helpful when searching by date.</p>
<p>For example instead of:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"> <span class="no">Widget</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="s1">'created_at > ? AND created_at < ?'</span><span class="p">,</span> <span class="mi">2</span><span class="p">.</span><span class="nf">hours</span><span class="p">.</span><span class="nf">ago</span><span class="p">,</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">)</span>
<span class="c1">#=> SELECT "widgets".* FROM "widgets" WHERE (created_at > '2011-06-18 03:38:58.493361' AND created_at < '2011-06-18 05:38:58.493442')</span></code></pre></figure>
<p>You can use a range, e.g.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"> <span class="no">Widget</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">:created_at</span> <span class="o">=></span> <span class="mi">2</span><span class="p">.</span><span class="nf">hours</span><span class="p">.</span><span class="nf">ago</span><span class="o">..</span><span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">)</span>
<span class="c1">#=> SELECT "widgets".* FROM "widgets" WHERE ("widgets"."created_at" BETWEEN '2011-06-18 03:36:53.551349' AND '2011-06-18 05:36:53.551489')</span></code></pre></figure>
<p>Notice how using an inclusive range produces a SQL BETWEEN query.</p>
<p>Using an exclusive range gives a different query.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"> <span class="no">Widget</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">:created_at</span> <span class="o">=></span> <span class="mi">2</span><span class="p">.</span><span class="nf">hours</span><span class="p">.</span><span class="nf">ago</span><span class="o">...</span><span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">)</span>
<span class="c1">#=> SELECT "widgets".* FROM "widgets" WHERE ("widgets"."created_at" >= '2011-06-11 05:25:12.738961' AND "widgets"."created_at" < '2011-06-18 05:25:12.739321')</span></code></pre></figure>
<p>Use carefully.</p>
<p>For an interesting use of this check out one of the new methods added to Rails 3.1 check out Date.today.all_day added <a href="https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/time/calculations.rb#L251-274">here</a>.</p>
Pxpay - Payment Express for Rails2011-05-15T00:00:00+00:00hhttps://www.bradleypriest.com/2011/05/15/pxpay-payment-express-for-rails
<p>Building websites in NZ invariably leads to integrating our most popular Payment Solution, Payment Express (DPS) over and over again.</p>
<p>Payment Express has two major options when it comes to online payments, the self-hosted version PxPost and the DPS-hosted version PxPay.</p>
<p>If you want to deal with credit card payments yourself using PxPost, the brilliant <a href="http://www.activemerchant.org">ActiveMerchant</a> has the PxPost gateway built into it.</p>
<p>However, for DPS-hosted payments, I couldn’t find any Ruby implementation, so I put one together myself.</p>
<p>I’ve put together the <a href="http://www.github.com/bradleypriest/pxpay">Pxpay</a> gem.</p>
<p>Obviously, dealing with payment data is something that has serious repercussions if something goes wrong, so be careful.</p>
<p>With that out of the way let’s take a look at how it works.</p>
<p>First things first, make sure you set up a development account with Payment Express <a href="https://www.paymentexpress.com/pxmi/apply">https://www.paymentexpress.com/pxmi/apply</a></p>
<p>With that out of the way install the gem and generate the config</p>
<p>This installs the gem and a pxpay.rb initializer to your config folder.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>gem <span class="nb">install </span>pxpay
<span class="nv">$ </span>rails generate pxpay:install</code></pre></figure>
<p>Firstly, make sure you update the initializer file with your credentials and optionally add the success and failure URLs for your app.</p>
<p>PxPay currently requires the <code class="language-plaintext highlighter-rouge">nokogiri</code> and <code class="language-plaintext highlighter-rouge">rest-client</code> gems.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o">>></span><span class="nb">require</span> <span class="s1">'nokogiri'</span>
<span class="o">>></span><span class="nb">require</span> <span class="s1">'pxpay'</span>
<span class="o">>></span><span class="n">request</span> <span class="o">=</span> <span class="no">Pxpay</span><span class="o">::</span><span class="no">Request</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">12.00</span> <span class="p">)</span>
<span class="o">=></span><span class="c1">#<Pxpay::Request:0x00000101c9a840></span>
<span class="o">>></span><span class="n">request</span><span class="p">.</span><span class="nf">url</span>
<span class="o">=></span> <span class="s2">"https://sec2.paymentexpress.com/pxpay/pxpay.aspx?userid=Fake_Dev&request=xxxxxxxxxx"</span></code></pre></figure>
<p>The Pxpay::Request object takes a unique ID, a price and an optional hash of arguments.</p>
<p>The important options are :url_success and :url_failure.</p>
<p>Other options include :merchant_reference, :currency and :email address.</p>
<p>Check the <a href="http://http://rubydoc.info/gems/pxpay/frames">documentation</a> for all the options.</p>
<p>In a rails app pass the arguments into PxPay::Request and redirect the customer to the returned URL.</p>
<p><em>order.rb</em></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">url</span>
<span class="vi">@url</span> <span class="o">=</span> <span class="no">Pxpay</span><span class="o">::</span><span class="no">Request</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span> <span class="nb">id</span> <span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="p">{</span>
<span class="ss">:email</span> <span class="o">=></span> <span class="n">user</span><span class="p">.</span><span class="nf">email</span><span class="p">,</span>
<span class="ss">:url_success</span> <span class="o">=></span> <span class="s2">"http://example.com/orders/</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">/success"</span><span class="p">,</span>
<span class="ss">:url_failure</span> <span class="o">=></span> <span class="s2">"http://example.com/orders/</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">/failure"</span>
<span class="p">})</span>
<span class="k">end</span></code></pre></figure>
<p>Payment Express will process the payments then redirect the customer back to either the success or failure URL.</p>
<p><em>orders_controller.rb</em></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">success</span>
<span class="n">response</span> <span class="o">=</span> <span class="no">Pxpay</span><span class="o">::</span><span class="no">Response</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">params</span><span class="p">).</span><span class="nf">response</span>
<span class="nb">hash</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">to_hash</span>
<span class="c1">## Do something with the results hash</span>
<span class="k">end</span></code></pre></figure>
<p>N.B. There is a minor caveat here: Payment Express includes a system called fail-proof result notification where as soon as the customer has finished the transaction they will send a background request.</p>
<p>This means your success/failure URL will be hit at least twice for each transaction, so you must allow for this in your code. See <a href="http://www.paymentexpress.com/technical_resources/ecommerce_hosted/pxpay.html#ResultNotification%20">here</a> for details.</p>
<p>That’s pretty much it. Any questions/problems hit me up on <a href="http://github.com/bradleypriest">Github</a></p>
Simple Rails Snippets2011-01-13T00:00:00+00:00hhttps://www.bradleypriest.com/2011/01/13/simple-rails-snippets
<p>There has been a bit of development around content micro-management in the Rails ecosystem lately.</p>
<p>Thoughtbot just released their hosted service <a href="http://www.copycopter.com">Copycopter</a>. Quickleft brought out the <a href="http://www.github.com/quickleft/regulate">Regulate</a> gem.</p>
<p>It’s really good to see some simple solutions to what should really be a simple problem.</p>
<p>For me, even these seem a bit much, if you just want to add really basic snippet management it really isn’t that hard to from scratch. I can’t promise you this is the best way to do it, but it works well for me, comments are greatly appreciated.</p>
<p>Start by creating a new Snippet model. I’m just going to use <a href="http://www.railscasts.com">Ryan Bates’</a> amazing <a href="http://www.github.com/ryanb/nifty-generators">nifty-generators</a>. All you really need is a name and content. I’m throwing in a status for drafts as well.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>rails generate nifty:scaffold Snippet title:string snippet:text status:string</code></pre></figure>
<p>Now let’s set up the basics: A simple helper</p>
<p><em>snippet_helper.rb</em></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">snippet_for</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="no">Rails</span><span class="p">.</span><span class="nf">cache</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="s2">"snippet::"</span><span class="o">+</span><span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">))</span> <span class="k">do</span>
<span class="no">Snippet</span><span class="p">.</span><span class="nf">published</span><span class="p">.</span><span class="nf">find_by_title</span><span class="p">(</span><span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">)</span> <span class="o">||</span> <span class="n">default</span> <span class="o">||</span> <span class="s2">"Snippet for </span><span class="si">#{</span><span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="si">}</span><span class="s2"> missing"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="kp">alias_method</span> <span class="ss">:s</span><span class="p">,</span> <span class="ss">:snippet_for</span></code></pre></figure>
<p>In the snippet helper I’m defining a snippet_for method:</p>
<p>This takes the name of the snippet, and an optional default value. Make sure you use descriptive names here, you’ll thank yourself later.</p>
<p>The helper will try to find a value first by searching the rails cache, followed by the snippet database, followed by the optional default and lastly will show a snippet not found message.</p>
<p>In the last line I’m aliasing snippet_for(…) to s(..) just for brevity</p>
<p><em>models/snippet.rb</em></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Snippet</span> <span class="o"><</span> <span class="no">ActiveModel</span>
<span class="n">after_save</span> <span class="ss">:clear_cache</span>
<span class="n">scope</span> <span class="ss">:published</span> <span class="n">where</span><span class="p">(</span><span class="ss">:status</span> <span class="o">=></span> <span class="s1">'published'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="n">snippet</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">clear_cache</span>
<span class="no">Rails</span><span class="p">.</span><span class="nf">cache</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="s2">"snippet::"</span><span class="o">+</span><span class="n">title</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p>The snippet model contains a simple published scope. And an after_save callback to allow for snippet updating. If you starting enhancing your snippet model you’ll probably want to implement a Rails sweeper.</p>
<p>Now in your code when you need a snippet</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o">=</span> <span class="n">snippet_for</span><span class="p">(</span><span class="ss">:call_to_action</span><span class="p">,</span> <span class="s1">'Click Me'</span><span class="p">)</span>
<span class="o">=</span> <span class="n">s</span><span class="p">(</span><span class="ss">:call_to_action</span><span class="p">,</span> <span class="s1">'Click Me'</span><span class="p">)</span></code></pre></figure>