<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Mechanical Bee</title>
 <link href="http://mechanicalbee.com/"/>
 <link type="application/atom+xml" rel="self" href="http://mechanicalbee.com/atom.xml"/> 
 <updated>2012-03-21T15:56:42-07:00</updated>
 <id>http://mechanicalbee.com/</id>
 <author>
   <name>Mechanical Bee</name>
   <email>hi@mechanicalbee.com</email>
 </author>

 
 <entry>
   <title>Obj to three.js, getting your materials to show up</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2012/obj-three-js-materials.html"/>
   <updated>2012-03-21T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2012/obj-three-js-materials</id>
   <content type="html">&lt;p&gt;We were playing around with &lt;a href='https://github.com/mrdoob/three.js/'&gt;three.js&lt;/a&gt; and nearly died of despair when we could not get the materials to show up on our completely black but otherwise perfect looking model for no discernible reason. In hindsight, our problem with light and not having it seems obvious but at the time, it was &lt;em&gt;really&lt;/em&gt; not obvious.&lt;/p&gt;

&lt;p&gt;So if someone gives you an obj file with some jpgs that are supposed to be the textures for the model and asks you to render it in your browser with three.js, here&amp;#8217;s what to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use the &lt;a href='https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender'&gt;blender exporter&lt;/a&gt; or the &lt;a href='https://github.com/mrdoob/three.js/tree/master/utils/exporters/obj'&gt;python obj exporter&lt;/a&gt; to turn your obj file into a js file.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Open that js file and you will see an array of materials at the top that looks like:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='s2'&gt;&amp;quot;materials&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[{&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;DbgColor&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;15658734&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;DbgIndex&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;DbgName&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;material_12.001&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;colorAmbient&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&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='mf'&gt;0.0111&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='s2'&gt;&amp;quot;colorDiffuse&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mf'&gt;0.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;0.009412000468552117&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;0.0&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;colorSpecular&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mf'&gt;1.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;1.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;1.0&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;mapDiffuse&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;room_50k_cleaned_noroof_tex012.jpg&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;mapDiffuseWrap&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;repeat&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;repeat&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;shading&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Lambert&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;specularCoef&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;transparency&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mf'&gt;0.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;vertexColors&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;false&lt;/span&gt;
&lt;span class='p'&gt;},{&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;DbgColor&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;15597568&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;DbgIndex&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;DbgName&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;material_13.001&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;colorAmbient&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&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='mf'&gt;0.0111&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='s2'&gt;&amp;quot;colorDiffuse&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mf'&gt;0.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;0.009412000468552117&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;0.0&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;colorSpecular&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mf'&gt;1.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;1.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mf'&gt;1.0&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;mapDiffuse&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;room_50k_cleaned_noroof_tex013.jpg&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;mapDiffuseWrap&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;repeat&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;repeat&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;shading&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Lambert&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;specularCoef&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;transparency&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mf'&gt;0.0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;vertexColors&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;false&lt;/span&gt;
&lt;span class='p'&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Notice how the &lt;code&gt;colorAmbient&lt;/code&gt; values are all close to 0. Change all of these to something like &lt;code&gt;[0.5, 0.5, 0.5]&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;colorAmbient&amp;quot; : [0.5, 0.5, 0.5]&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Using the &lt;a href='https://github.com/jeromeetienne/threejsboilerplate'&gt;three.js boilerplate&lt;/a&gt;, move your js file into the js folder and the texture images into the images folder.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Open up the index.html of the boilerplate and get rid of the sample object.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Add an ambient light:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;ambient&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;THREE&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;AmbientLight&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='mh'&gt;0xFFFFFF&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;scene&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;ambient&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Load your js file with the JSONLoader and MeshFaceMaterial:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;THREE&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;JSONLoader&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;js/your_js_file_path_.js&amp;#39;&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;geometry&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;mesh&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;THREE&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Mesh&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;geometry&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;THREE&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;MeshFaceMaterial&lt;/span&gt;&lt;span class='p'&gt;());&lt;/span&gt;
  &lt;span class='nx'&gt;scene&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;mesh&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;},&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;images&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Finally start the local server and navigate to &lt;a href='http://localhost:8000'&gt;localhost:8000&lt;/a&gt; in your browser.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;make server&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Organizing a large backbone and rails app, some thoughts</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/organizing-a-large-backbone-rails-app.html"/>
   <updated>2011-12-17T00:00:00-08:00</updated>
   <id>http://mechanicalbee.com/2011/organizing-a-large-backbone-rails-app</id>
   <content type="html">&lt;p&gt;We recently started working on a new web app with backbone 0.5.3, rails 3.1, and couchdb. It&amp;#8217;s not the still-raw-and-pulsing bleeding edge but it&amp;#8217;s pretty new stuff. There are some nice examples of backbone apps, e.g. &lt;a href='https://github.com/documentcloud/documentcloud'&gt;DocumentCloud&lt;/a&gt;, &lt;a href='http://cloudapp.github.com/engine/'&gt;CloudApp&lt;/a&gt;, &lt;a href='http://cloudedit.jamesyu.org/'&gt;CloudEdit&lt;/a&gt;, &lt;a href='http://documentcloud.github.com/backbone/examples/todos/index.html'&gt;Todo&lt;/a&gt;, etc., but conventions and best practices aren&amp;#8217;t there yet in the way that they are for Rails.&lt;/p&gt;

&lt;p&gt;Our app is larger than any of these examples so we thought we&amp;#8217;d share how we&amp;#8217;re currently organizing it, and handling routing, forms, and nested models.&lt;/p&gt;

&lt;h3 id='folders_and_files'&gt;Folders and Files&lt;/h3&gt;

&lt;p&gt;Our app files and directory structure are very similar to that of &lt;a href='https://github.com/codebrew/backbone-rails'&gt;backbone-rails&lt;/a&gt; with a few differences. backbone-rails creates four folders under app/assets/javascripts/backbone:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;routers/
models/
templates/
views/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our app is in stealth mode right now so let&amp;#8217;s say it&amp;#8217;s a web app to connect Jarls, Guild Masters, and other quest givers with adventurers who want to do quests. Quest givers and quest takers have similar but different UI requirements. For example, they both look at quests but quest givers can edit the quest and see all the quest takers who are interested in the quest, etc. So instead of one backbone folder for the entire app, we&amp;#8217;ve got folders for both groups and a folder for shared assets:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;app/assets/javascripts/quest_givers 
app/assets/javascripts/quest_takers
app/assets/javascripts/shared&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='routing'&gt;Routing&lt;/h3&gt;

&lt;p&gt;There are two types of routes the backbone app needs to know about.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;backend rails routes so that models can sync with the server&lt;/li&gt;

&lt;li&gt;front-end routes for navigating around, triggering views and actions, etc&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the backend routes, we could just set it on the Collection e.g.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;QuestGiver&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Collections&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;QuestCollection&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Collection&lt;/span&gt;
  &lt;span class='nx'&gt;url&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/quest&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Instead we added an application.js.erb file to our rails app and filled a Skyrim.Routes object using the rails helpers. Something like:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;Skyrim&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{}&lt;/span&gt;
&lt;span class='nx'&gt;Skyrim&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;quest_givers_quests_path&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;%= quest_givers_quests_path %&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then our Collection url is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;url: Skyrim.Routes.quest_givers_quests_path&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Front-end routes are used in a couple places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in the backbone routers, typically:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;QuestsRouter&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Router&lt;/span&gt;
  &lt;span class='nx'&gt;routes&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; 
    &lt;span class='s2'&gt;&amp;quot;quests&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;index&amp;quot;&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;quests/new&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;newQuest&amp;quot;&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;quests/:id&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;show&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;in the backbone views for example when switching from new to show after a model is saved:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;QuestGiver&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Views&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Quests&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;NewView&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Views&lt;/span&gt;
  &lt;span class='nx'&gt;save&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;collection&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='err'&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;toJSON&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt;
      &lt;span class='nx'&gt;success&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;quest&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;model&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;quest&lt;/span&gt;
        &lt;span class='nb'&gt;window&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;location&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;hash&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/#{@model.id}&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;in the jst templates in places like the href of anchor tags e.g. :&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='nt'&gt;&amp;lt;a&lt;/span&gt; &lt;span class='na'&gt;href=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;#/&amp;lt;%= id %&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;Show Quest&lt;span class='nt'&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;However we wanted our routes defined in one place so we added a Routes object:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='nb'&gt;window&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt;
  &lt;span class='nx'&gt;quests&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/quests&amp;#39;&lt;/span&gt;
  &lt;span class='nx'&gt;new_quest&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/quests/new&amp;#39;&lt;/span&gt;
  &lt;span class='nx'&gt;quest&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/quests/:id&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then we used a slightly modified version of &lt;a href='https://gist.github.com/877784'&gt;router.js&lt;/a&gt; and pass QuestGivers.Routes to addRoutes(). Now our routers, views, and templates look like:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;QuestsRouter&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Router&lt;/span&gt;
  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;options&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;routes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{}&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;routes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;quests&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;index&amp;#39;&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;routes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;new_quest&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;newQuest&amp;#39;&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;routes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;quest&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;show&amp;#39;&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;_bindRoutes&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Don&amp;#8217;t forget to _bindRoutes() when adding routes this way or they won&amp;#8217;t get triggered.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;QuestGiver&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Views&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Quests&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;NewView&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Views&lt;/span&gt;
  &lt;span class='nx'&gt;save&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;collection&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='err'&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;toJSON&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt;
      &lt;span class='nx'&gt;success&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;quest&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class='err'&gt;@&lt;/span&gt;&lt;span class='nx'&gt;model&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;quest&lt;/span&gt;
        &lt;span class='nb'&gt;window&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;location&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;hash&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;QuestGivers&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Routes&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;quest&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='err'&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;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='nt'&gt;&amp;lt;a&lt;/span&gt; &lt;span class='na'&gt;href=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;&amp;lt;%= QuestGivers.Routes.quest(id) %&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;Show Quest&lt;span class='nt'&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='forms_and_nested_models'&gt;Forms and Nested Models&lt;/h3&gt;

&lt;p&gt;We&amp;#8217;re not using the &lt;a href='https://github.com/codebrew/backbone-rails'&gt;backbone-rails gem&lt;/a&gt; but we are using the &lt;a href='https://github.com/codebrew/backbone-rails/blob/master/vendor/assets/javascripts/backbone_datalink.js'&gt;datalink plugin&lt;/a&gt; to connect models with form fields and the &lt;a href='https://github.com/codebrew/backbone-rails/blob/master/vendor/assets/javascripts/backbone_rails_sync.js'&gt;rails-ified Backbone.sync&lt;/a&gt;. We&amp;#8217;re also using &lt;a href='https://github.com/powmedia/backbone-deep-model'&gt;backbone-deep-model&lt;/a&gt; so that we can do:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;QuestGiver&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Models&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Quest&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;DeepModel&lt;/span&gt;
  &lt;span class='nx'&gt;defaults&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; 
    &lt;span class='nx'&gt;name&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;
    &lt;span class='nx'&gt;address&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;Skyrim&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Models&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Address&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    
&lt;span class='kr'&gt;class&lt;/span&gt; &lt;span class='nx'&gt;Skyrim&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Models&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Address&lt;/span&gt; &lt;span class='kr'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Model&lt;/span&gt;
  &lt;span class='nx'&gt;defaults&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
    &lt;span class='nx'&gt;address&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;
    &lt;span class='nx'&gt;city&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;
    &lt;span class='nx'&gt;state&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;
    &lt;span class='nx'&gt;zipcode&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;

&lt;span class='nx'&gt;model&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;QuestGiver&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Models&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Quest&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;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;address.city&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='going_forward'&gt;Going Forward&lt;/h3&gt;

&lt;p&gt;We&amp;#8217;re just getting started so maybe in a few months we&amp;#8217;ll look back on this and shake our heads in wonder. We&amp;#8217;ll see where it goes!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Why I'll (probably) never use CoffeeScript</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/why-ill-never-use-coffeescript.html"/>
   <updated>2011-10-12T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/why-ill-never-use-coffeescript</id>
   <content type="html">&lt;p&gt;We started a new project using &lt;a href='http://rubyonrails.org/'&gt;Rails 3.1&lt;/a&gt;, so I was checking out all the new stuff in this release. Most of it looks great, since the new baked in features solve problems that we were using third party or home grown solutions for anyway. On our last project (Rails 3.0), we used &lt;a href='http://lesscss.org/'&gt;Less&lt;/a&gt; and &lt;a href='http://documentcloud.github.com/jammit/'&gt;Jammit&lt;/a&gt;. On this one, we use &lt;a href='http://sass-lang.com/'&gt;Sass&lt;/a&gt; and &lt;a href='https://github.com/sstephenson/sprockets'&gt;Sprockets&lt;/a&gt;. Rails chose for us and that&amp;#8217;s great, because now we don&amp;#8217;t have to deal with it. But there&amp;#8217;s one new feature that I just don&amp;#8217;t get: &lt;a href='http://jashkenas.github.com/coffee-script/'&gt;CoffeeScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I mean, I get it. Javascript has a lot of pomp and isn&amp;#8217;t a whole lot of fun to code in. But it&amp;#8217;s the only language that the browser runs and that&amp;#8217;s a &lt;em&gt;real&lt;/em&gt; constraint. If I write my client-side code in CoffeeScript, the browser still receives and runs Javascript. That creates a huge disconnect between what I&amp;#8217;m writing and what I&amp;#8217;m running. Now maybe your code runs perfectly every time, but mine doesn&amp;#8217;t. And when it doesn&amp;#8217;t, I look at what&amp;#8217;s happening in the debugger. What do I see in the debugger if I use CoffeeScript? Not my code, but a &lt;em&gt;derivative&lt;/em&gt; of my code. What do I have to do to fix a bug? Mentally decompile the running Javascript to the source CoffeeScript, make the change in the CoffeeScript, and hope that it compiles back down to the Javascript that fixes my problem. Harsh.&lt;/p&gt;

&lt;p&gt;The problem here is that CoffeeScript fails at it&amp;#8217;s fundamental purpose as an &lt;strong&gt;abstraction&lt;/strong&gt;: removing me from the underlying complexity. It in no way removes me from having to deeply understand Javascript. In fact, it &lt;em&gt;increases&lt;/em&gt; complexity because now I have to know Javascript and CoffeeScript and be able to mentally translate between the two.&lt;/p&gt;

&lt;p&gt;Now, as forward thinking person, I do see the value in alternate client side languages. I suspect that if lots of devs start using CoffeeScript or &lt;a href='http://www.dartlang.org/'&gt;Dart&lt;/a&gt; or whatever, the browsers will eventually implement some kind of native support for these languages, which will be great. But this is a long way off and probably requires one language to dominate and all browsers to support it. I&amp;#8217;m just not willing to let my own code suffer for years helping this to happen. Maybe you are, and for that I appreciate your sacrifice.&lt;/p&gt;

&lt;p&gt;You can check out our new CoffeeScript-free project at &lt;a href='http://wheretoeatat.com/'&gt;wheretoeatat.com&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Geek fun: building a lil' node.js app</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/building-a-small-node-app-on-heroku.html"/>
   <updated>2011-07-28T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/building-a-small-node-app-on-heroku</id>
   <content type="html">&lt;p&gt;We recently wrote a little service in Node.js and &lt;a href='http://devcenter.heroku.com/articles/node-js'&gt;deployed it on Heroku&amp;#8217;s Cedar stack&lt;/a&gt;. All it does is return UPS shipping rates when we do an http get with certain parameters. So instead of hitting UPS directly every time an &lt;a href='https://www.givmo.com/items/ad22badf6f3d59481ea9b9bd54f45352'&gt;item page&lt;/a&gt; loads, we hit the node app and it either pulls the rate out of Redis or asks UPS, meaning that shipping rates should come up a lot faster. We didn&amp;#8217;t &lt;em&gt;really&lt;/em&gt; need to spin up a Node app for this but hey, this is how we have fun :D.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a pretty basic app but there were a couple modules we used for the various pieces:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query string parsing - &lt;a href='https://github.com/visionmedia/node-querystring'&gt;qs&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Caching - &lt;a href='http://devcenter.heroku.com/articles/redistogo'&gt;RedisToGo&lt;/a&gt; and &lt;a href='https://github.com/mranney/node_redis'&gt;redis&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;XML templating and parsing - &lt;a href='https://github.com/raycmorgan/Mu'&gt;Mu&lt;/a&gt; and &lt;a href='https://github.com/Leonidas-from-XIV/node-xml2js'&gt;xml2js&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And as an auxiliary bonus, anyone can use it to get UPS public rates.&lt;/p&gt;

&lt;h3 id='node_modules'&gt;Node modules&lt;/h3&gt;

&lt;h4 id='qs'&gt;qs&lt;/h4&gt;

&lt;p&gt;Heroku runs Node v0.4.7 and there&amp;#8217;s an included &lt;a href='http://nodejs.org/docs/v0.4.7/api/querystring.html'&gt;query string module&lt;/a&gt; that parses the query string into an object. But we wanted to send nested parameters like &amp;#8216;destination[state]=NJ&amp;amp;destination[zip]=07305&amp;#8217;. &lt;a href='https://github.com/visionmedia/node-querystring'&gt;qs&lt;/a&gt; adds back the parsing of nested parameters that apparently got removed in 0.3.x. For example, hit http://localhost:8080/?destination[state]=NJ&amp;amp;destination[zip]=07305 in your browser while running this with node locally:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;http&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='s1'&gt;&amp;#39;http&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='nx'&gt;qs&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='s1'&gt;&amp;#39;qs&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='nx'&gt;url&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='s1'&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;http&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;createServer&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;request&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&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;query&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;url&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;parse&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;url&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;end&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;stringify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;qs&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;parse&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;)));&lt;/span&gt;
&lt;span class='p'&gt;}).&lt;/span&gt;&lt;span class='nx'&gt;listen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;8080&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='redis'&gt;redis&lt;/h4&gt;

&lt;p&gt;We don&amp;#8217;t charge flat shipping rates, it&amp;#8217;s just whatever UPS says it is and it&amp;#8217;s based on a &lt;a href='http://blog.givmo.com/2011/08/why-is-shipping-so-expensive/'&gt;number of factors&lt;/a&gt;. But since there are only 7 zones in the continental US and most things on Givmo are within 1-15 pounds, there&amp;#8217;s a small set of probably base rates, ripe for caching.&lt;/p&gt;

&lt;p&gt;We decided to use redis partly because it seemed like the node community preferred it and partly because we thought it&amp;#8217;d be fun. So we added the &lt;a href='http://addons.heroku.com/redistogo'&gt;Nano plan for RedisToGo on Heroku&lt;/a&gt; and &lt;a href='https://github.com/mranney/node_redis'&gt;node_redis&lt;/a&gt;, hooking them up with &lt;a href='http://blog.jerodsanto.net/2011/06/connecting-node-js-to-redis-to-go-on-heroku/'&gt;this little snippet&lt;/a&gt;. Each key is set to expire after 24 hrs.&lt;/p&gt;

&lt;h4 id='mustache_and_xml2js'&gt;mustache and xml2js&lt;/h4&gt;

&lt;p&gt;The XML going back and forth is one of the annoying aspects of the UPS api. For the request, we made an XML file with &lt;a href='http://mustache.github.com/mustache.5.html'&gt;mustache template tags&lt;/a&gt;. A snippet:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;ShipTo&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;Address&amp;gt;&lt;/span&gt;
    {{#destination}}
    &lt;span class='nt'&gt;&amp;lt;PostalCode&amp;gt;&lt;/span&gt;{{zip}}&lt;span class='nt'&gt;&amp;lt;/PostalCode&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;StateProvinceCode&amp;gt;&lt;/span&gt;{{state}}&lt;span class='nt'&gt;&amp;lt;/StateProvinceCode&amp;gt;&lt;/span&gt;
    {{/destination}}
    {{#residential}}&lt;span class='nt'&gt;&amp;lt;ResidentialAddress&lt;/span&gt; &lt;span class='nt'&gt;/&amp;gt;&lt;/span&gt;{{/residential}}
  &lt;span class='nt'&gt;&amp;lt;/Address&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/ShipTo&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then &lt;a href='https://github.com/raycmorgan/Mu'&gt;mu&lt;/a&gt; to compile and render the template. When UPS returned an XML response, we used &lt;a href='https://github.com/Leonidas-from-XIV/node-xml2js'&gt;xml2js&lt;/a&gt; because it was simple and we liked how it mapped &lt;a href='http://blog.nodejitsu.com/6-must-have-nodejs-modules'&gt;XML to a js object&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id='get_public_rates'&gt;GET public rates&lt;/h3&gt;

&lt;p&gt;Anyone can use this to get UPS public rates. Why would you want to use it instead of the real UPS api though?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Faster (&lt;a href='http://techcrunch.com/2011/08/08/amazon-ec2-outage/'&gt;except when AWS goes down and takes out Heroku/the internet&lt;/a&gt;).&lt;/li&gt;

&lt;li&gt;Easier: No need to get a key or deal with xml.&lt;/li&gt;

&lt;li&gt;Just for fun :)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here are some ways to use it:&lt;/p&gt;

&lt;p&gt;&lt;a href='http://hollow-spring-510.herokuapp.com/?destination[state]=NJ&amp;amp;destination[zip]=07305&amp;amp;origin[state]=NC&amp;amp;origin[zip]=27713&amp;amp;residential=false&amp;amp;weight=4'&gt;From your browser&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Node.js:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;http&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='s2'&gt;&amp;quot;http&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
  &lt;span class='nx'&gt;qs&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='s2'&gt;&amp;quot;qs&amp;quot;&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;query&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;qs&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stringify&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;origin&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nx'&gt;state&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;NC&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;zip&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;27713&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;},&lt;/span&gt;
  &lt;span class='nx'&gt;destination&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='nx'&gt;state&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;NY&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;zip&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;10001&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;},&lt;/span&gt;
  &lt;span class='nx'&gt;weight&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;20&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='nx'&gt;residential&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;true&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;options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='nx'&gt;host&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hollow-spring-510.herokuapp.com&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='nx'&gt;path&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/?&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;query&lt;/span&gt;
&lt;span class='p'&gt;};&lt;/span&gt;

&lt;span class='nx'&gt;http&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;options&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;res&lt;/span&gt;&lt;span class='p'&gt;){&lt;/span&gt;
  &lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setEncoding&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;utf8&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;on&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;data&amp;#39;&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;chunk&lt;/span&gt;&lt;span class='p'&gt;){&lt;/span&gt;
    &lt;span class='nx'&gt;console&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;log&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;chunk&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='nx'&gt;on&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;error&amp;#39;&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;e&lt;/span&gt;&lt;span class='p'&gt;){&lt;/span&gt;
  &lt;span class='nx'&gt;console&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;log&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Error: &amp;quot;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;message&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;With Ruby:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;rest_client&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;params&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;RestClient&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Payload&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;generate&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
  &lt;span class='ss'&gt;:origin&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='ss'&gt;:state&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;NC&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:zip&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;27713&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;},&lt;/span&gt;
  &lt;span class='ss'&gt;:destination&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='ss'&gt;:state&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;NY&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:zip&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;11211&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;},&lt;/span&gt;
  &lt;span class='ss'&gt;:residential&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='p'&gt;,&lt;/span&gt;
  &lt;span class='ss'&gt;:weight&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;
&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='no'&gt;RestClient&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;http://hollow-spring-510.herokuapp.com/?&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>couch_record: a new CouchDB ORM for Ruby on Rails</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/couch_record-a-new-couchdb-orm-for-ruby-on-rails.html"/>
   <updated>2011-07-13T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/couch_record-a-new-couchdb-orm-for-ruby-on-rails</id>
   <content type="html">&lt;p&gt;We&amp;#8217;ll write a more detailed post about it later but we&amp;#8217;re excited to open this up now: couch_record, a new couchDB ORM for Ruby on Rails, using couchrest and based on our experiences with &lt;a href='https://github.com/couchrest/couchrest_model'&gt;couchrest_model&lt;/a&gt; and, to a lesser extent, couchrest_rails.&lt;/p&gt;

&lt;h3 id='why_do_we_need_another_couchdb_orm'&gt;Why do we need another CouchDB ORM?&lt;/h3&gt;

&lt;p&gt;When we were deciding which ORM to use, it seemed like &lt;a href='https://github.com/couchrest/couchrest_model'&gt;couchrest_model&lt;/a&gt; had the most traction and most activity. But there were a number of aspects we were unhappy with (we wrote about one of them &lt;a href='/2011/performance-issues-couchrest-activemodel.html'&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Then recently we added &lt;a href='http://addons.heroku.com/newrelic'&gt;New Relic&lt;/a&gt; and noticed some really problematic performance issues with our &lt;a href='https://www.givmo.com/items'&gt;items&lt;/a&gt; page (to the point where we were restarting our app every 20 minutes to keep response times reasonable). We pinpointed the issue to a memory leak from &lt;a href='https://github.com/couchrest/couchrest_model'&gt;couchrest_model&lt;/a&gt;. We were a couple versions behind and the latest version fixed our problem but also introduced a number of new things that didn&amp;#8217;t work with the rest of our app. So we decided to roll our own with these goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Be Fast&lt;/strong&gt; - Your app has to map a lot of objects, so try to do as little as possible, especially when reading records from CouchDB&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Be Simple&lt;/strong&gt; - You&amp;#8217;re going to end up looking at (debugging into) your ORM when something&amp;#8217;s not working as you expect, so the less code there is and the easier it is to understand, the better.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ActiveModel&lt;/strong&gt; - Use ActiveModel modules wherever possible to support ActiveModel functionality&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;#8217;t Support Everything&lt;/strong&gt; - CouchRecord is not a drop in replacement for ActiveRecord, CouchRest::Model or anything else&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We made this for ourselves so it very specifically addresses our needs and the tests and documentation are a bit oblique but we&amp;#8217;d love for other people to try it out and find it useful in their own projects!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Why we don't use the Heroku SendGrid addon</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/sendgrid_heroku_addon.html"/>
   <updated>2011-07-10T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/sendgrid_heroku_addon</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: When you use Heroku&amp;#8217;s SendGrid add-on, your account is a sub-user of the main Heroku account and doesn&amp;#8217;t get manually provisioned or tiered based on goodness like solo SendGrid accounts. This means that the IP group your in is more likely to be populated with miscreants whose bad behavior decreases your own deliverability. So if you&amp;#8217;re not a miscreant and don&amp;#8217;t want to get lumped in with other miscreants, you should just sign up for a normal SendGrid account&amp;#8212;the &lt;a href='http://sendgrid.com/pricing.html'&gt;pricing/plans&lt;/a&gt; are the same or better anyways.&lt;/p&gt;

&lt;h4 id='using_sendgrid_via_the_heroku_addon_is_braindead_easy'&gt;Using SendGrid via the Heroku addon is brain-dead easy&lt;/h4&gt;

&lt;p&gt;Using a normal SendGrid account with a Rails app is easy&amp;#8212;sign up for an account and modify the &lt;a href='http://edgeguides.rubyonrails.org/action_mailer_basics.html#example-action-mailer-configuration'&gt;smtp config for action mailer&lt;/a&gt;. You know what&amp;#8217;s easier though? Clicking a button. And that&amp;#8217;s how the &lt;a href='http://devcenter.heroku.com/articles/sendgrid'&gt;Heroku SendGrid add-on&lt;/a&gt; works: click a button and SendGrid starts delivering your app&amp;#8217;s emails. With no discernible difference in features or price, we picked the easiest option and activated the Heroku SendGrid add-on. Ticket complete.&lt;/p&gt;

&lt;p&gt;But then people started complaining that they hadn&amp;#8217;t received their confirmation email or password reset email in 6, 12, 24 hours. What was going on?&lt;/p&gt;

&lt;p&gt;At this point, we have to pause to commend SendGrid support. We were at a Hackathon for &lt;a href='http://www.internetweekny.com/'&gt;New York Internet Week&lt;/a&gt; and mentioned to a SendGrid engineer that we had noticed some problems with deliverability. He said he&amp;#8217;d inquire with his compatriots and honestly we didn&amp;#8217;t really believe him since a) we said it in a joking tone, b) they were visiting New York from Cali and who wants to remember complaints from randoms on another coast, and c) we are tiny fish in their vast ocean, paying exactly nothing. But he did and they were so responsive and solicitous, we were astonished they could get any work done in between their many detailed, specific emails.&lt;/p&gt;

&lt;h4 id='sharing_with_sketchballs_makes_you_look_sketchy'&gt;Sharing with sketchballs makes you look sketchy&lt;/h4&gt;

&lt;p&gt;So what was going on with our emails? We signed in to Sendgrid with the account credentials Heroku had created for us (use &lt;em&gt;heroku config&lt;/em&gt; to get your username and password) and under the email activity tab, found that a number of emails had been &amp;#8220;deferred&amp;#8221; with these errors:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;reason: 452 4.2.2 The email account that you tried to reach is over quota. Please direct the recipient to http://mail.google.com/support/bin/answer.py?answer=6558 z5si15616573yhh.117 (throttled)

reason: 450 4.2.1 The user you are trying to contact is receiving mail at a rate that prevents additional messages from being delivered. Please resend your message at a later time. If the user is able to receive mail at that time, your message will be delivered. For more information, please visit http://mail.google.com/support/bin/answer.py?answer=6592 w4si8027019anc.83 (throttled)

reason: 421 4.7.0 [TS01] Messages from 67.228.50.54 temporarily deferred due to user complaints - 4.16.55.1; see http://postmaster.yahoo.com/421-ts01.html (throttled)

reason: 421 4.7.0 [TS01] Messages from 67.228.50.55 temporarily deferred due to user complaints - 4.16.55.1; see http://postmaster.yahoo.com/421-ts01.html (throttled)&amp;lt;/pre&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From the help links in the first two errors, it looks like the problem is with the recipient. But based on the latter two errors, it looks like the problem is with emails coming from the ip addresses. Everyone using the Heroku SendGrid addon gets added as a subuser to the master Heroku account and shares an IP group. This means that if other subusers are up to no good, efforts to curb their sketchy email will affect our legitimate email as well. The obvious solution is to switch to one of the SendGrid plans that include a dedicated IP address but we preferred the price of our current plan (free).&lt;/p&gt;

&lt;h4 id='if_you_must_share_pick_a_good_neighborhood'&gt;If you must share, pick a good neighborhood&lt;/h4&gt;

&lt;p&gt;What we discovered: all normal SendGrid accounts get manually provisioned and those without dedicated IPs get sorted into tiers based on goodness. Accounts that get added through Heroku, since they are subusers of the Heroku account, don&amp;#8217;t go through either of these filters.&lt;/p&gt;

&lt;p&gt;From our favorite SendGrid engineer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8230;Our Bronze and Free packages are generally a bit better than Heroku. One reason for this is; Free or Bronze accounts are tiered IP groups based on reputation, so if you guys are not bouncing a lot of emails and don&amp;#8217;t have many complaints you will filter into the highest tier of IPs which will have better delivery rates than the lower tiers. I believe we have four tiers total, so that gives some better granularity to pair better customers with better customers rather than lumping you all together.&lt;/p&gt;

&lt;p&gt;This tiering doesn&amp;#8217;t happen on Heroku accounts, so everyone is all together, good, bad, or ugly&amp;#8230;&lt;/p&gt;

&lt;p&gt;&amp;#8230;the fact that there is an increased complaint rate on the Heroku IP group means someone is not behaving themselves and is probably sending out either something resembling spam, or to a list that they didn&amp;#8217;t &lt;em&gt;really&lt;/em&gt; opt in. Either way, this bad for all the rest of the upstanding citizens on the Heroku IP Group. So, we will need to look into this and see if we can find an eliminate the guilty party. Heroku accounts unfortunately are a bit more prone to this, as the accounts are subject to Heroku on-boarding procedures, and thus get to skip the SendGrid manual provisioning process&amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Heroku is great for many reasons, one of them being the addons ecosystem. Just don&amp;#8217;t use the Heroku SendGrid add-on to add SendGrid to your Rails app. We&amp;#8217;ve discovered that it&amp;#8217;s well worth the extra 10 minutes required to sign up for your own account; we&amp;#8217;ve since switched to a normal SendGrid account and have noticed significantly fewer problems.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to auto reload gems that you're working on in Rails 3</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/autoreload-gems-rails-3.html"/>
   <updated>2011-06-28T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/autoreload-gems-rails-3</id>
   <content type="html">&lt;p&gt;We recently moved our &lt;a href='https://github.com/givmo/couch_record'&gt;CouchDB ORM&lt;/a&gt; code into its own Ruby gem because we&amp;#8217;re thinking about making it open source. While working on the new ORM gem in the context of the Givmo Rails app, I wanted the the gem code to reload on every request like the rest of the code for the app. For a while I was making frequent changes and restarting the server every time got old pretty fast.&lt;/p&gt;

&lt;p&gt;I eventually figured out how to do this, but it wasn&amp;#8217;t super easy to find, so here&amp;#8217;s the short, sweet version of what you&amp;#8217;ll need to do:&lt;/p&gt;
&lt;script src='https://gist.github.com/1051936.js'&gt; &lt;/script&gt;
&lt;p&gt;First in development.rb, you need to add the lib directory for your gem to the autoload path. This is because gems normally only get loaded once, on startup. Since we want it to reload, we use the Rails autoload system. Files only autoload if the relevant constant is missing, so the last step is to tell rails to unload the root constant for our gem on every request.&lt;/p&gt;

&lt;p&gt;Then in your Gemfile, tell bundler to load the gem in question from wherever you&amp;#8217;re working on it. In this case, it&amp;#8217;s in a sister directory to the Rails app.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to find your SendGrid login when using the Heroku addon</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/sendgrid-login-on-heroku.html"/>
   <updated>2011-06-12T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/sendgrid-login-on-heroku</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re using the Heroku SendGrid addon, they&amp;#8217;ll create account credentials for you. e.g. a username and password. Sometimes you want to either do some configuration or more frequently, log in to the SendGrid site to see stats and activity and stuff.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;heroku config&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and you&amp;#8217;ll see a bunch of config vars. The ones you&amp;#8217;re looking for are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SENDGRID_USERNAME
SENDGRID_PASSWORD
SENDGRID_DOMAIN&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Omniauth, openid, heroku, and https</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/omniauth-openid-heroku-and-https.html"/>
   <updated>2011-05-11T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/omniauth-openid-heroku-and-https</id>
   <content type="html">&lt;p&gt;We recently added the option to log in or sign up with Facebook, Twitter, or Google using the handy &lt;a href='https://github.com/intridea/omniauth'&gt;omniauth&lt;/a&gt; gem.&lt;/p&gt;

&lt;p&gt;Facebook and Twitter went swimmingly. We had already been integrating with Facebook and Twitter so that people could tweet or post to Facebook to tell their friends about the items they&amp;#8217;re giving away. Adding a sign up/log in pathway was just an extension of that functionality.&lt;/p&gt;

&lt;p&gt;But we ran into a problem with Google and OpenID: they worked fine in development but kept failing with &amp;#8220;invalid credentials&amp;#8221; in production.&lt;/p&gt;

&lt;p&gt;There are two main differences with our production environment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It&amp;#8217;s on Heroku which has a &lt;a href='http://devcenter.heroku.com/articles/read-only-filesystem'&gt;read-only system&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;It always runs over https&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We looked at possible problems with writing to the filesystem on Heroku first. Even though we had the &lt;a href='http://kent.posterous.com/omniauth-rails-3-heroku-google-apps-tempfile'&gt;filesystem path set to ./tmp&lt;/a&gt;, we were still worried about it and thought about &lt;a href='http://www.arailsdemo.com/posts/18'&gt;switching to a memcache store&lt;/a&gt;. But then we tested another app on Heroku with the same filesystem store writing to ./tmp and that worked fine.&lt;/p&gt;

&lt;p&gt;Okay maybe it was a problem with ssl. This turned out to be really hard to google because we kept trying some combination of &amp;#8220;Omniauth openid heroku https&amp;#8221; (thus the blatant google mongering of this title) but in fact the problem was with Rack. We&amp;#8217;re using rails 3.0.3, omniauth 0.2.5, devise 1.3.4, and rack 1.2.2. The &lt;a href='https://github.com/rack/rack/blob/1.3.0.beta/lib/rack/request.rb'&gt;1.3.0.beta version&lt;/a&gt; of rack has a notably different request.rb from the &lt;a href='https://github.com/rack/rack/blob/1.2.2/lib/rack/request.rb'&gt;1.2.2 version&lt;/a&gt;. Notice the scheme and port methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;request.rb&lt;/em&gt; in rack 1.2.2:&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;scheme&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;          &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;rack.url_scheme&amp;quot;&lt;/span&gt;&lt;span class='o'&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;port&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;            &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SERVER_PORT&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;to_i&lt;/span&gt;                 &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;request.rb&lt;/em&gt; in rack 1.3.0.beta:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;scheme&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;HTTPS&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;on&amp;#39;&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;https&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;HTTP_X_FORWARDED_SSL&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;on&amp;#39;&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;https&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;HTTP_X_FORWARDED_PROTO&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;HTTP_X_FORWARDED_PROTO&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&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='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='k'&gt;else&lt;/span&gt;
    &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;rack.url_scheme&amp;quot;&lt;/span&gt;&lt;span class='o'&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;def&lt;/span&gt; &lt;span class='nf'&gt;port&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;host_with_port&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;split&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='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='n'&gt;port&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_i&lt;/span&gt;
  &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='n'&gt;port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;HTTP_X_FORWARDED_PORT&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='n'&gt;port&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_i&lt;/span&gt;
  &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='n'&gt;ssl?&lt;/span&gt;
    &lt;span class='mi'&gt;443&lt;/span&gt;
  &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;has_key?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;HTTP_X_FORWARDED_HOST&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='mi'&gt;80&lt;/span&gt;
  &lt;span class='k'&gt;else&lt;/span&gt;
    &lt;span class='vi'&gt;@env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SERVER_PORT&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;to_i&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When we go to /auth/google in production, rack 1.2.2 doesn&amp;#8217;t realize we&amp;#8217;re coming from https and the return_to for OpenID gets set to http. In development, this was fine because everything is http but in production, OpenID does a verification on the return_to url and raises a ProtocolError when the schemes don&amp;#8217;t match.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href='https://github.com/openid/ruby-openid/blob/master/lib/openid/consumer/idres.rb'&gt;idres.rb:199&lt;/a&gt;&lt;/em&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:scheme&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:host&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:port&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:path&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;each&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;meth&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;msg_return_to&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;meth&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='n'&gt;app_parsed&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;meth&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;raise&lt;/span&gt; &lt;span class='no'&gt;ProtocolError&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;return_to &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;meth&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_s&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; does not match&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then the OpenID strategy in omniauth fails with the not so useful &amp;#8220;invalid credentials&amp;#8221; message.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href='https://github.com/intridea/omniauth/blob/v0.2.5/oa-openid/l%20ib/omniauth/strategies/open_id.rb'&gt;open_id.rb:91&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='vi'&gt;@openid_response&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;delete&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;rack.openid.response&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='vi'&gt;@openid_response&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='vi'&gt;@openid_response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;status&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:success&lt;/span&gt;
  &lt;span class='k'&gt;super&lt;/span&gt;
&lt;span class='k'&gt;else&lt;/span&gt;
  &lt;span class='nb'&gt;fail&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:invalid_credentials&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;We ended up monkeypatching it with &lt;a href='https://gist.github.com/825769'&gt;this code&lt;/a&gt; and it seems to be working so far.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Performance issues with CouchRest::Model and ActiveModel</title>
   <link type="text/html" rel="alternate" href="http://mechanicalbee.com/2011/performance-issues-couchrest-activemodel.html"/>
   <updated>2011-05-03T00:00:00-07:00</updated>
   <id>http://mechanicalbee.com/2011/performance-issues-couchrest-activemodel</id>
   <content type="html">&lt;p&gt;For &lt;a href='https://www.givmo.com'&gt;Givmo&lt;/a&gt;, we have an admin page that lists about 100 records at a time and it was taking upwards of 10 seconds to load. It doesn&amp;#8217;t do anything super complicated, so I didn&amp;#8217;t really have a good starting point for what to optimize. Time to fire up the profiler.&lt;/p&gt;

&lt;p&gt;The page in question loads 100 records (documents) from a &lt;a href='http://couchdb.apache.org'&gt;CouchDB&lt;/a&gt; database and displays them to the user in a table. Nothin&amp;#8217; crazy. We use &lt;a href='https://github.com/couchrest/couchrest_model'&gt;CouchRest Model&lt;/a&gt; to do our ORM, which makes our model classes behave like ActiveModels. This makes them more or less compatible with tools that like to work with ActiveRecord.&lt;/p&gt;

&lt;p&gt;I wrapped the offending code with the &lt;a href='https://github.com/rdp/ruby-prof'&gt;ruby-prof gem&lt;/a&gt; and generated some profiling data. After some digging, I found that all the time was being spent in 2 methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-respond_to-3F'&gt;ActiveModel::AttributeMethods#respond_to?&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-method_missing'&gt;ActiveModel::AttributeMethods#method_missing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CouchRest::Model doesn&amp;#8217;t create accessors for the model&amp;#8217;s properties. Instead, it keeps a list of all the properties (if you&amp;#8217;re looking, it&amp;#8217;s in &lt;a href='https://github.com/givmo/couchrest_model/blob/master/lib/couchrest/model/properties.rb'&gt;couchrest_model/lib/couchrest/model/properties.rb&lt;/a&gt;) and lets activemodel&amp;#8217;s #method_missing deal with it (&lt;a href='https://github.com/rails/rails/blob/v3.0.3/activemodel/lib/active_model/attribute_methods.rb'&gt;activemodel/lib/active_model/attribute_methods.rb&lt;/a&gt;). So when a record is being loaded from the database and you have a property called &amp;#8216;email&amp;#8217;, it first checks #respond_to? to see if there&amp;#8217;s a setter (#email=) and then calls the setter which triggers #method_missing.&lt;/p&gt;

&lt;p&gt;Both #respond_to? and #method_missing have to do roughly the same thing: check if there&amp;#8217;s a property named &amp;#8216;email&amp;#8217; in the list of properties. They both call the same method to do this: #match_attribute_method?. This method (and its children) could use some optimization. It maps the array of Properties to an array of property names (creating a new array of names every call) and then loops through the new array looking for the name. For 100 records with 10 properties, this gets called about 20,000 times. Ouch.&lt;/p&gt;

&lt;p&gt;So, for this particular page, I cut CouchRest::Model out of the picture. The time to render the page went from 10 seconds to 0.077 seconds. That&amp;#8217;s 2 orders of magnitude folks.&lt;/p&gt;

&lt;p&gt;Incidentally, the query to get the data from the &lt;a href='http://cloudant.com/'&gt;Cloudant&lt;/a&gt; server, over the internet, though my measly cable modem takes about 0.5 seconds. Something doesn&amp;#8217;t feel right with it taking 20 times longer to map the data into objects than it does to load it from the database.&lt;/p&gt;

&lt;p&gt;Oh and we&amp;#8217;re on Rails 3.0.3 and couchrest_model 1.0.0.beta8.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
