<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>CodeOfficer.com</title>
  <subtitle>A web developer in Maine</subtitle>
  <id>http://codeofficer.com/</id>
  <link href="http://codeofficer.com/"/>
  <link href="http://codeofficer.com/feed.xml" rel="self"/>
  <updated>2013-11-20T21:11:00Z</updated>
  <author>
    <name>Russell Jones</name>
  </author>
  <entry>
    <title>Preloading Fixture Data with Ember App Kit</title>
    <link rel="alternate" href="/blog/2013/11/20/preloading-fixture-data-with-ember-app-kit.html"/>
    <id>/blog/2013/11/20/preloading-fixture-data-with-ember-app-kit.html</id>
    <published>2013-11-20T21:11:00Z</published>
    <updated>2013-11-20T21:11:00Z</updated>
    <author>
      <name>Russell Jones</name>
    </author>
    <content type="html">&lt;p&gt;I&amp;rsquo;m currently using &lt;a href="https://github.com/stefanpenner/ember-app-kit"&gt;Ember App Kit&lt;/a&gt; on a client project and really enjoying the environment. Javascript build tools are what they are but Stefan Penner and crew have done a phenomenal job at making them not suck. I am ever so grateful.&lt;/p&gt;

&lt;p&gt;Application needs vary of course, but mine delivers 85% of its data up front in one big payload. It&amp;rsquo;s safe for me to assume in production that this data will be there when the app is run, and data that isn&amp;rsquo;t will be fetched as needed via the RESTAdapter. In development and testing however, I&amp;rsquo;m using the FixtureAdapter which unfortunately doesn&amp;rsquo;t autoload non-async relationships defined in the model, even though the fixture data is there. I needed this data to behave in development and testing as it would in production. Fortunately, I stumbled upon &lt;a href="http://amalgamated.io/emberjs-and-fixtures/"&gt;a blog post&lt;/a&gt; over at &lt;strong&gt;Amalgamated Magic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Below, I&amp;rsquo;ve made their solution work for Ember App Kit. I believe there are plans to make EAK&amp;rsquo;s resolver better at loading initializers for you, but for now this works.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;app/initializers/force_load_fixtures&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;initializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;force load fixtures&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;store&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;store:main&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;Ember&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requirejs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_eak_seen&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^appkit\/models\//&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;DS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;typeKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^appkit\/models\/(.*)/&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FIXTURES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typeKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FIXTURES&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;initializer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Then in &lt;code&gt;app.js&lt;/code&gt; load and execute our initializer:&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;forceLoadFixturesInitializer&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;appkit/initializers/force_load_fixtures&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Ember&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;Ember&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;forceLoadFixturesInitializer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Enjoy.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Ember Data: Faking a Composite Key</title>
    <link rel="alternate" href="/blog/2013/10/03/ember-data-faking-a-composite-key.html"/>
    <id>/blog/2013/10/03/ember-data-faking-a-composite-key.html</id>
    <published>2013-10-03T20:11:00Z</published>
    <updated>2013-10-03T20:11:00Z</updated>
    <author>
      <name>Russell Jones</name>
    </author>
    <content type="html">&lt;p&gt;I play a game in my spare time called Guild Wars 2 which recently made a public API for their community to build applications against. Among other things, it allows you to query for game events as they are happening in real time, which helps you play more efficiently. I started working on a little side project which takes it a step further and draws you a map of the surrounding area. It&amp;rsquo;s a work in progress, but you can &lt;a href="https://github.com/CodeOfficer/guild-wars-2-event-notifier"&gt;check it out&lt;/a&gt; on Github.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve been working with &lt;a href="http://emberjs.com/"&gt;Ember&lt;/a&gt; and &lt;a href="https://github.com/emberjs/data"&gt;Ember Data&lt;/a&gt; for a little over a year now and use this project as a study to keep up on their latest and greatest features. I can&amp;rsquo;t say enough good things about Ember as a framework for javascript web applications, but this post is really about Ember Data.&lt;/p&gt;

&lt;p&gt;While Ember Data has had its growing pains as a persistance library it&amp;rsquo;s shaping up quite nicely. I like how the new Beta&amp;rsquo;s adapter and serializer allow you to customize data coming into and going out of your app on a per-model basis. Particularly when building for a 3rd party API, you really need proper hooks to fine-tune the data exchange with your RESTful backend.&lt;/p&gt;

&lt;p&gt;In earlier versions of Ember Data I found myself having to copy/paste/edit sizable chunks of library code into my own custom adapter or serializer. The necessary hooks were not present. This time around, I&amp;rsquo;m finding hooks in all the right places.&lt;/p&gt;

&lt;p&gt;Straight from my project, here&amp;rsquo;s an example customization I did for the MapFloor model:&lt;/p&gt;

&lt;h3&gt;MapFloor Model&lt;/h3&gt;

&lt;p&gt;The json for the MapFloor endpoint does not return an &lt;code&gt;id&lt;/code&gt; attribute. If you insert a model into the store without an &amp;lsquo;id&amp;rsquo;, the store will not know how to uniquely identiy that model from others of that type. One solution is to sythensize your own &amp;lsquo;id&amp;rsquo; in the returned json. This is something you would usually do in the serializer for the model.&lt;/p&gt;

&lt;p&gt;Complicating matters, the MapFloor endpoint also requires two &lt;code&gt;ids&lt;/code&gt; to fetch a single MapFloor, composed of a &lt;code&gt;continent_id&lt;/code&gt; and a &lt;code&gt;floor&lt;/code&gt; &amp;hellip; yet the json reponse does not return those values at all.&lt;/p&gt;

&lt;p&gt;To clarify, this is what I need to hit:&lt;/p&gt;
&lt;pre class="highlight text"&gt;https://api.guildwars2.com/v1/map_floor?continent_id=1&amp;amp;floor=2
&lt;/pre&gt;
&lt;p&gt;And this is what I get back:&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;span class="c1"&gt;// notice there is no &amp;#39;id&amp;#39; in this payload
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;texture_dims&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;32768&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;regions&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// lots of data map floor data
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;I felt I really wanted to be able to do something like:&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mapFloor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;1.2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;1.2&lt;/code&gt; would expand to to the appropriate endpoint URL. My changes seemed appropriate for the adapter, especially since I also wanted to pass those values back to the serializer. This is the custom adapter I ended up with for my MapFloor model.&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;span class="c1"&gt;// App.ApplicationAdapter = DS.ActiveModelAdapter.extend();
&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MapFloorAdapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ApplicationAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

  &lt;span class="na"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;continent_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;floor_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;buildURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;parseId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;?continent_id=%@&amp;amp;floor=%@&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;continent_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;floor_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;parseId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buildURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;continent_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;continent_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parseId&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;floor_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;pathForType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Ember&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;underscore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;My custom implementation of &lt;code&gt;find&lt;/code&gt; parses my fake composite &lt;code&gt;id&lt;/code&gt; and remembers its &lt;code&gt;continent_id&lt;/code&gt; and &lt;code&gt;floor_id&lt;/code&gt; values. Those values are used to construct the endpoint URL and also set values on the returned json. All this will later get handed off to the serializer and because the payload now includes a sythesized &lt;code&gt;id&lt;/code&gt; the store will be happy and able to uniquely identify this specific MapFloor in the future.&lt;/p&gt;

&lt;p&gt;Lastly, I overrode &lt;code&gt;pathForType&lt;/code&gt; since I needed to hit a singularized version of the resource URL.&lt;/p&gt;

&lt;p&gt;Hope you find this approach to faking a composite key in Ember Data useful.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Custom Built Guild Wars 2 Gaming Rig</title>
    <link rel="alternate" href="/blog/2012/04/14/custom-built-guild-wars-2-gaming-rig.html"/>
    <id>/blog/2012/04/14/custom-built-guild-wars-2-gaming-rig.html</id>
    <published>2012-04-14T07:21:00Z</published>
    <updated>2012-04-14T07:21:00Z</updated>
    <author>
      <name>Russell Jones</name>
    </author>
    <content type="html">&lt;p&gt;My good friend &lt;a href="mailto:john1253113@gmail.com"&gt;John Coppola&lt;/a&gt; recently told me that he had built his own CNC machine from scratch. Soon afterwards we discussed the idea that he would build my next gaming computer. I knew from personal experience how killer John&amp;rsquo;s computers were &amp;hellip; he&amp;rsquo;s very meticulous, and really enjoys a cutom build. As excited as I was, I really didn&amp;rsquo;t know what to expect when he told me this one would be 100% of his own making, but I&amp;rsquo;ll get back to this &amp;hellip;&lt;/p&gt;

&lt;p class="video-container"&gt;
  &lt;iframe src="http://youtube.com/embed/HszCWPcsnFA?rel=0" frameborder="0" allowfullscreen&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In truth, I haven&amp;rsquo;t gamed much since 2006 when my wife and I got married, bought a house and had our first baby. I was a year or so into &lt;a href="http://us.battle.net/wow/en/"&gt;World of Warcraft&lt;/a&gt; then and had been agressively playing MMOs since 2001. I&amp;rsquo;d have dropped gaming all together that year if it weren&amp;rsquo;t for my fortunate discovery of Guild Wars.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spoiler Alert: once you have kids you just can&amp;rsquo;t continue gaming like you used to.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://guildwars.com/"&gt;Guild Wars&lt;/a&gt; was sort of like World of Warcraft for me, but geared more toward the casual gamer. More importantly, it had an MMO feel but there were no costly subscription fees. I didn&amp;rsquo;t feel compelled to play when I might have had more important things to do. When &lt;a href="http://www.guildwars2.com/en/"&gt;Guild Wars 2&lt;/a&gt; was announced I knew right away I would be picking up my copy. I was also glad to hear that there would still be no subscription fees. Hallelujah!&lt;/p&gt;

&lt;p&gt;To celebrate, I wanted to do something special and decided to go all out on building a proper gaming rig. John knew how to make this happen. I was already thoroughly intrigued by his CNC machine and come to find out, he had already put 200 hours into this custom case design he had in mind. Boy did that get my attention!&lt;/p&gt;

&lt;p&gt;I could never have known how cool this machine would end up, and how perfectly it would fit my needs. You&amp;rsquo;ll notice that despite the etching on the side, there&amp;rsquo;s even a Guild Wars 2 look about it. Honestly, the etching was an afterthought. Johk John actually jokes that he chose white acrylic to make the case with because I was a mac guy and would eat it right up. He was right I guess. I present to you, the fruit of John&amp;rsquo;s labor &amp;hellip;&lt;/p&gt;

&lt;ul class="thumbnails"&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-01.png"&gt;&lt;img src="/images/computer/thumbs/Computer-01.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-02.png"&gt;&lt;img src="/images/computer/thumbs/Computer-02.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-04.png"&gt;&lt;img src="/images/computer/thumbs/Computer-04.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-05.png"&gt;&lt;img src="/images/computer/thumbs/Computer-05.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-06.png"&gt;&lt;img src="/images/computer/thumbs/Computer-06.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-08.png"&gt;&lt;img src="/images/computer/thumbs/Computer-08.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-09.png"&gt;&lt;img src="/images/computer/thumbs/Computer-09.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-10.png"&gt;&lt;img src="/images/computer/thumbs/Computer-10.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-11.png"&gt;&lt;img src="/images/computer/thumbs/Computer-11.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-13.png"&gt;&lt;img src="/images/computer/thumbs/Computer-13.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-14.png"&gt;&lt;img src="/images/computer/thumbs/Computer-14.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-15.png"&gt;&lt;img src="/images/computer/thumbs/Computer-15.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-17.png"&gt;&lt;img src="/images/computer/thumbs/Computer-17.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-18.png"&gt;&lt;img src="/images/computer/thumbs/Computer-18.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-20.png"&gt;&lt;img src="/images/computer/thumbs/Computer-20.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-21.png"&gt;&lt;img src="/images/computer/thumbs/Computer-21.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-22.png"&gt;&lt;img src="/images/computer/thumbs/Computer-22.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-24.png"&gt;&lt;img src="/images/computer/thumbs/Computer-24.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-26.png"&gt;&lt;img src="/images/computer/thumbs/Computer-26.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-27.png"&gt;&lt;img src="/images/computer/thumbs/Computer-27.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-28.png"&gt;&lt;img src="/images/computer/thumbs/Computer-28.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-29.png"&gt;&lt;img src="/images/computer/thumbs/Computer-29.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-30.png"&gt;&lt;img src="/images/computer/thumbs/Computer-30.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-32.png"&gt;&lt;img src="/images/computer/thumbs/Computer-32.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-33.png"&gt;&lt;img src="/images/computer/thumbs/Computer-33.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-34.png"&gt;&lt;img src="/images/computer/thumbs/Computer-34.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-36.png"&gt;&lt;img src="/images/computer/thumbs/Computer-36.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-37.png"&gt;&lt;img src="/images/computer/thumbs/Computer-37.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-40.png"&gt;&lt;img src="/images/computer/thumbs/Computer-40.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-41.png"&gt;&lt;img src="/images/computer/thumbs/Computer-41.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li class="span2"&gt;&lt;a class="thumbnail" href="/images/computer/large/Computer-42.png"&gt;&lt;img src="/images/computer/thumbs/Computer-42.png" alt="" /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are the system specs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16814125421"&gt;&lt;strong&gt;Videocard&lt;/strong&gt; - GIGABYTE NVIDIA GeForce GTX 680&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16819115230"&gt;&lt;strong&gt;CPU&lt;/strong&gt; - Intel i5-2550K Sandy Bridge 3.4GHz Quad-Core (overclocked to 4.5GHz)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16813128495"&gt;&lt;strong&gt;Motherboard&lt;/strong&gt; - GIGABYTE Intel Z68 Micro ATX (HackinTosh compatable)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820147134"&gt;&lt;strong&gt;SSD&lt;/strong&gt; - SAMSUNG 830 Series MZ-7PC128D/AM 2.5&amp;quot; 128GB SATA III&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820161452"&gt;&lt;strong&gt;Memory&lt;/strong&gt; - Wintec One 8GB (2 x 4GB) 240-Pin DDR3 SDRAM DDR3 1600 (PC3 12800)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16817703036"&gt;&lt;strong&gt;Power Supply&lt;/strong&gt; - PC Power and Cooling Silencer MK III&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16832116986"&gt;&lt;strong&gt;OS&lt;/strong&gt; - Microsoft Windows 7 Home Premium SP1 64-bit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;cPath=36_69_1060&amp;products_id=27385"&gt;&lt;strong&gt;Fans&lt;/strong&gt; - Xigmatek &amp;ldquo;Crystal Series&amp;rdquo; 120x25mm LED (x6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;cPath=59_971_498_493&amp;products_id=31146"&gt;&lt;strong&gt;CPU water block&lt;/strong&gt; - Swiftech APOGEE XTL Water Block&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;cPath=59_457_667_668&amp;products_id=26776"&gt;&lt;strong&gt;Radiators&lt;/strong&gt; - EK-CoolStream RAD XT (x2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;products_id=29204"&gt;&lt;strong&gt;Pump converter&lt;/strong&gt; - Swiftech D5 Pump Housing Custom G1/4 Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;products_id=28303"&gt;&lt;strong&gt;Pump&lt;/strong&gt; - Swiftech MCP655™ Series 12 VDC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;products_id=22838:93d0ea543e48c8d289f8d4776e034769"&gt;&lt;strong&gt;Anti-kink coils&lt;/strong&gt; - PrimoChill Clear (x2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;cPath=59_413_992_974&amp;products_id=30313"&gt;&lt;strong&gt;Tubing&lt;/strong&gt; - Masterkleer Tubing PVC 13/10mm UV-reactive White&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;cPath=59_971_240_579&amp;products_id=33725"&gt;&lt;strong&gt;Videocard water block&lt;/strong&gt; - EK-FC680 GTX for nVidia Reference Design GeForce GTX 680 (Nickel)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;products_id=33562"&gt;&lt;strong&gt;Fillport&lt;/strong&gt; - XSPC M20 to G1/4&amp;quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;products_id=21501"&gt;&lt;strong&gt;Tubing connectors&lt;/strong&gt; - Danger Den G1/4 High Flow Stubby Fittings (x18)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;cPath=59_346_393_620&amp;products_id=24758"&gt;&lt;strong&gt;90 Degree fittings&lt;/strong&gt; - Bitspower G &amp;frac14;&amp;quot; Black Sparkle 90 Degree IG &amp;frac14;&amp;quot; Adapter (x4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.iogear.com/press/presskit/ces2012/GCS1924/GCS1924_Datasheet.pdf"&gt;&lt;strong&gt;KVMP Switch&lt;/strong&gt; - IOGEAR 4-port DualView Mini DisplayPort KVMP Switch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://estore.circuitassembly.com/products/Mini-Displayport-Female-to-Displayport-Male-Adapter-Cable.html"&gt;&lt;strong&gt;Cable&lt;/strong&gt; - MDP Female to DP Male Adapter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you would like to have John make you something similar, feel free to contact him directly: &lt;a href="mailto:john1253113@gmail.com"&gt;john1253113@gmail.com&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Use Association Extensions to Build Join Attributes on a HMT</title>
    <link rel="alternate" href="/blog/2012/04/03/use-association-extensions-to-build-join-attributes-on-a-hmt.html"/>
    <id>/blog/2012/04/03/use-association-extensions-to-build-join-attributes-on-a-hmt.html</id>
    <published>2012-04-03T07:36:00Z</published>
    <updated>2012-04-03T07:36:00Z</updated>
    <author>
      <name>Russell Jones</name>
    </author>
    <content type="html">&lt;p&gt;It&amp;rsquo;s common in Rails to use a &lt;code&gt;has_many :through&lt;/code&gt; relationship to model User/Group Memberships.
Sometimes we have extra data in the join that we would like to make use of, but getting that
data in there can be combersome depending on our approach. For example, given the
following diagram and schema:&lt;/p&gt;

&lt;p&gt;&lt;img alt="Diagram" src="/images/mine/yumlcb495048.png" /&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;&lt;span class="nf"&gt;.define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:version&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20120324170519&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;groups&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:force&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.string&lt;/span&gt;   &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.datetime&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.datetime&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;memberships&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:force&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.integer&lt;/span&gt;  &lt;span class="s2"&gt;&amp;quot;user_id&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.integer&lt;/span&gt;  &lt;span class="s2"&gt;&amp;quot;group_id&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.string&lt;/span&gt;   &lt;span class="s2"&gt;&amp;quot;role&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.datetime&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.datetime&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:force&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.string&lt;/span&gt;   &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.datetime&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.datetime&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;We might deal directly with the join table to assign our additonal data.&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;User 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Group&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Group 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vi"&gt;@membership&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Membership&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="nf"&gt;.user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;
  &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="nf"&gt;.group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@group&lt;/span&gt;
  &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="nf"&gt;.role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="nf"&gt;.admin?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="nf"&gt;.editor?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s a better way to pull this off &amp;hellip;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="vi"&gt;@group&lt;/span&gt;&lt;span class="nf"&gt;.admins&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="nf"&gt;.admin?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="nf"&gt;.editor?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And this is how it&amp;rsquo;s done &amp;hellip;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="k"&gt;class &lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:memberships&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:groups&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:through&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:memberships&lt;/span&gt;

  &lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nf"&gt;admin?&lt;/span&gt;
    &lt;span class="n"&gt;memberships&lt;/span&gt;&lt;span class="nf"&gt;.where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:role&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.first&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nf"&gt;editor?&lt;/span&gt;
    &lt;span class="n"&gt;memberships&lt;/span&gt;&lt;span class="nf"&gt;.where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:role&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;editor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.first&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;span class="k"&gt;class &lt;/span&gt;&lt;span class="nc"&gt;Membership&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:group&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;span class="k"&gt;class &lt;/span&gt;&lt;span class="nc"&gt;Group&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:memberships&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:through&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:memberships&lt;/span&gt;

  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:admins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:through&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:memberships&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:source&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;memberships.role = &amp;#39;admin&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;proxy_association&lt;/span&gt;&lt;span class="nf"&gt;.owner.memberships.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:role&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:editors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:through&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:memberships&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:source&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;memberships.role = &amp;#39;editor&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;proxy_association&lt;/span&gt;&lt;span class="nf"&gt;.owner.memberships.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:role&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;editor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;We&amp;rsquo;re defining an extension on our group&amp;rsquo;s &lt;code&gt;has_many&lt;/code&gt; association which overrides
the &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; method on that collection. We then tell the proxy association&amp;rsquo;s owner
(which is our group object) to create the user/group join record, but with an additional
role assignment of &amp;lsquo;admin&amp;rsquo;.&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="vi"&gt;@group&lt;/span&gt;&lt;span class="nf"&gt;.admins&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="nf"&gt;.admin?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="nf"&gt;.editor?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Pretty expressive, thanks to ActiveRecord!&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;test_helper&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class &lt;/span&gt;&lt;span class="nc"&gt;GroupTest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestCase&lt;/span&gt;
  &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@user_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;User 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@user_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;User 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@user_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;User 3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Group&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Group 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;No Memberships&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_1&lt;/span&gt;&lt;span class="nf"&gt;.memberships.count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;@group.users &amp;lt;&amp;lt; @user_1 sets nil role on membership&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@group&lt;/span&gt;&lt;span class="nf"&gt;.users&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@user_1&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_1&lt;/span&gt;&lt;span class="nf"&gt;.memberships.count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_1&lt;/span&gt;&lt;span class="nf"&gt;.memberships.first.role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;@group.admins &amp;lt;&amp;lt; @user_2 sets &amp;#39;admin&amp;#39; role on membership&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@group&lt;/span&gt;&lt;span class="nf"&gt;.admins&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@user_2&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_2&lt;/span&gt;&lt;span class="nf"&gt;.memberships.count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_2&lt;/span&gt;&lt;span class="nf"&gt;.memberships.first.role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;@group.editors &amp;lt;&amp;lt; @user_3 sets &amp;#39;editor&amp;#39; role on membership&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@group&lt;/span&gt;&lt;span class="nf"&gt;.editors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="vi"&gt;@user_3&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_3&lt;/span&gt;&lt;span class="nf"&gt;.memberships.count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="vi"&gt;@user_3&lt;/span&gt;&lt;span class="nf"&gt;.memberships.first.role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;editor&amp;#39;&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;teardown&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="nf"&gt;.delete_all&lt;/span&gt;
    &lt;span class="no"&gt;Group&lt;/span&gt;&lt;span class="nf"&gt;.delete_all&lt;/span&gt;
    &lt;span class="no"&gt;Membership&lt;/span&gt;&lt;span class="nf"&gt;.delete_all&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;</content>
  </entry>
  <entry>
    <title>Easy environment specific seed files in Rails 3</title>
    <link rel="alternate" href="/blog/2010/09/30/Easy-environment-specific-seed-files-in-Rails-3.html"/>
    <id>/blog/2010/09/30/Easy-environment-specific-seed-files-in-Rails-3.html</id>
    <published>2010-09-30T07:36:00Z</published>
    <updated>2010-09-30T07:36:00Z</updated>
    <author>
      <name>Russell Jones</name>
    </author>
    <content type="html">&lt;p&gt;Tonight I discovered a &lt;a href="https://rails.lighthouseapp.com/projects/8994/tickets/4908-feature-request-db-seed-files-for-each-environment"&gt;lighthouse ticket&lt;/a&gt; by &lt;a href="http://houseofpostmodern.wordpress.com/"&gt;Postmodern&lt;/a&gt;. In it, he asks about adding an environment aware feature to the existing &amp;lsquo;rake db:seed&amp;rsquo; task, so that he could seed specific environments differently. He even includes &lt;a href="http://github.com/postmodern/rails/commit/7dd0718239c6747e1a6981aed9b9c406532e9828"&gt;a patch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you haven&amp;rsquo;t used rails &amp;lsquo;rake db:seed&amp;rsquo; functionality, its quite handy. I use it primarily during the pre-launch phase of development to fill out my app with dummy data, most of which is generated using the &lt;a href="http://github.com/EmmanuelOga/ffaker"&gt;ffaker&lt;/a&gt; gem. That all works fine for me!&lt;/p&gt;

&lt;p&gt;Up until &amp;hellip; the time that my client wants to see progress and I need to deploy my code to a staging server. For that I require an entirely different set of seed data. Try as I might, I just can&amp;rsquo;t get the client used to my beloved &amp;ldquo;Lorem ipsum dolor&amp;rdquo;. So, environment aware seeding is very useful to me.&lt;/p&gt;

&lt;p&gt;A neat thing about rake tasks is that when you redeclare a task, it doesnt overwrite the previous one. So, to use postmodern&amp;rsquo;s patch all you have to do is paste the following code to the bottom of your Rakefile and you&amp;rsquo;ll reap the full benefits.&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:db&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:seed&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;env_seed_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="nf"&gt;.root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;db&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;seeds&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="nf"&gt;.env&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env_seed_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="nf"&gt;.exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env_seed_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now you can do stuff like this! (the env specific file is loaded after the regular seeds file)&lt;/p&gt;
&lt;pre class="highlight text"&gt;db
+-- seeds
|   +-- development.rb
|   +-- production.rb
|   +-- staging.rb
+-- seeds.rb
&lt;/pre&gt;
&lt;p&gt;Thanks Postmodern&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Form builders in Rails: field names and ids for Javascript</title>
    <link rel="alternate" href="/blog/2010/09/27/form-builders-in-rails-field-names-and-ids-for-javascript.html"/>
    <id>/blog/2010/09/27/form-builders-in-rails-field-names-and-ids-for-javascript.html</id>
    <published>2010-09-27T08:50:00Z</published>
    <updated>2010-09-27T08:50:00Z</updated>
    <author>
      <name>Russell Jones</name>
    </author>
    <content type="html">&lt;p&gt;I came up with a few convenience methods today which will help you discover what Rail&amp;rsquo;s generated NAME and ID attributes will be for a specific field on a given form builder object. Actually, I didn&amp;rsquo;t come up with them so much as extract them from the built in form builder. It was useful enough to me that I thought I might share my discovery. I can&amp;rsquo;t tell you how many times I&amp;rsquo;ve lazily hardcoded an ID onto a form element just to bypass the defaults.&lt;/p&gt;

&lt;p&gt;Throw these 2 methods in your ApplicationHelper module:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nf"&gt;field_id_for_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.object_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="nf"&gt;.to_s.sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\?$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt;&lt;span class="nf"&gt;.gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\]\[|[^-a-zA-Z0-9:.]/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/_$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nf"&gt;field_name_for_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.object_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="nf"&gt;.to_s.sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\?$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here is an example using Rails nested attribute forms:&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@submission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="nf"&gt;.fields_for&lt;/span&gt; &lt;span class="ss"&gt;:project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@submission&lt;/span&gt;&lt;span class="nf"&gt;.project&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;field&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.label&lt;/span&gt; &lt;span class="ss"&gt;:classified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Classified?&amp;quot;&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.radio_button&lt;/span&gt; &lt;span class="ss"&gt;:classified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt; &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.label&lt;/span&gt; &lt;span class="ss"&gt;:classified_false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;No&amp;quot;&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.radio_button&lt;/span&gt; &lt;span class="ss"&gt;:classified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.label&lt;/span&gt; &lt;span class="ss"&gt;:classified_true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Yes&amp;quot;&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;content_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
        $(function() {
          // get our value by name
          $(&amp;quot;input[name=&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;field_name_for_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:classified&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;]&amp;quot;).val();
          // set our value by ID
          $(&amp;quot;#&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;field_id_for_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:classified_true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;checked&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Would output:&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// get our value by name
&lt;/span&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;input[name=&amp;#39;submission[project_attributes][classified]&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// set our value by ID
&lt;/span&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#submission_project_attributes_classified_true&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;checked&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In case you missed it &amp;hellip;&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;field_name_for_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:classified&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;field_id_for_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:classified_true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;&amp;hellip; produced &amp;hellip;&lt;/p&gt;
&lt;pre class="highlight text"&gt;submission[project_attributes][classified]
submission_project_attributes_classified_true
&lt;/pre&gt;
&lt;p&gt;Pretty handy stuff&lt;/p&gt;
</content>
  </entry>
</feed>
