<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>MetaSkills.net - Home</title>
  <id>tag:www.metaskills.net,2008:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  <link href="http://www.metaskills.net/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://www.metaskills.net/" rel="alternate" type="text/html"/>
  <updated>2008-06-18T15:50:02Z</updated>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-06-18:156</id>
    <published>2008-06-18T02:41:00Z</published>
    <updated>2008-06-18T15:50:02Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="ajax"/>
    <category term="csrf"/>
    <category term="javascript"/>
    <category term="rails"/>
    <category term="rest"/>
    <link href="http://www.metaskills.net/2008/6/18/restful-ajax-with-forgery-protection" rel="alternate" type="text/html"/>
    <title>RESTful AJAX with Forgery Protection</title>
<summary type="html">&lt;p&gt;
  Writing the new &lt;a href=&quot;http://www.homemarks.com/&quot; class=&quot;external-link&quot;&gt;HomeMarks&lt;/a&gt; has been a great exercise. I've learned that the &lt;a href=&quot;/2008/5/24/the-ajax-head-br-design-pattern&quot;&gt;&lt;em&gt;AJAX Head &amp;lt;strike&gt;Design Pattern&amp;lt;/strike&gt; Implementation&lt;/em&gt;&lt;/a&gt; is more akin to developing a service-oriented application (SOA) since I have moved all client-side coupling from the controllers, like RJS, and only respond with HEAD or JSON data. Today I learned...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;
  Writing the new &lt;a href=&quot;http://www.homemarks.com/&quot; class=&quot;external-link&quot;&gt;HomeMarks&lt;/a&gt; has been a great exercise. I've learned that the &lt;a href=&quot;/2008/5/24/the-ajax-head-br-design-pattern&quot;&gt;&lt;em&gt;AJAX Head &amp;lt;strike&gt;Design Pattern&amp;lt;/strike&gt; Implementation&lt;/em&gt;&lt;/a&gt; is more akin to developing a service-oriented application (SOA) since I have moved all client-side coupling from the controllers, like RJS, and only respond with HEAD or JSON data. Today I learned...&lt;/p&gt;
&lt;p&gt;
  Writing the new &lt;a href=&quot;http://www.homemarks.com/&quot; class=&quot;external-link&quot;&gt;HomeMarks&lt;/a&gt; has been a great exercise. I've learned that the &lt;a href=&quot;/2008/5/24/the-ajax-head-br-design-pattern&quot;&gt;&lt;em&gt;AJAX Head &amp;lt;strike&gt;Design Pattern&amp;lt;/strike&gt; Implementation&lt;/em&gt;&lt;/a&gt; is more akin to developing a service-oriented application (SOA) since I have moved all client-side coupling from the controllers, like RJS, and only respond with HEAD or JSON data. Today I learned about &lt;a href=&quot;http://halcyon.rubyforge.org/&quot; class=&quot;external-link&quot;&gt;Halcyon&lt;/a&gt; which is self described as a JSON web application framework built on Rack. If you take a look at their example, it looks a lot like HomeMarks v2, pretty cool!
&lt;/p&gt;

&lt;h3&gt;Getting To The Point&lt;/h3&gt;

&lt;p&gt;
  Last week I finally got around to doing the controller CRUD for the user's column objects. The core &lt;code&gt;homemarks/app.js&lt;/code&gt; JavaScript class contains the one (and only one) AJAX dispatcher/handler for the entire application. One problem that I ran into was how to continue to use forgery protection in rails to protect from CSRF attacks while relying solely on ad-hoc JavaScript requests to a RESTful back-end. I could have turned off &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/RequestForgeryProtection/ClassMethods.html#M000300&quot; class=&quot;external-link&quot;&gt;&lt;code&gt;protect_from_forgery&lt;/code&gt;&lt;/a&gt; but that did not feel right. I wanted RESTful AJAX with forgery protection.
&lt;/p&gt;

&lt;h3&gt;My Solution&lt;/h3&gt;

&lt;p&gt;
  Since the HomeMarks v2 app has one AJAX dispatcher/handler for the entire app, all I had to do was to get the authenticity token into each and every request. It took a bit of digging in the rails source to find the methods I wanted but here both the ERB snippet I am using in my layout and the helper method found in my &lt;code&gt;application_helper.rb&lt;/code&gt; file.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;ta&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;text/javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;&amp;lt;%= auth_params_js_var %&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;ta&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;auth_params_js_var&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;RAILS_ENV&lt;/span&gt; == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%|&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var authParams = $H({&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;request_forgery_protection_token&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;form_authenticity_token.inspect&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;});&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;
  What does this do? It creates a JS variable called &lt;code&gt;authParams&lt;/code&gt; at the window level (right term?) that all other functions can use. That variable returns a JavaScript hash that will have a single key/value pair for the rails authenticity token, see below. Basically at this point all you have to do is merge this hash with your &lt;code&gt;parameters&lt;/code&gt; option for your AJAX object. You can reference the HomeMarks app.js file in the resources section if you want to see how I did this on my app, code snippet below too.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  doAjaxRequest: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(elmnt,finishMethod) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; method = elmnt.method || &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;    new Ajax.Request(elmnt.action,{&lt;tt&gt;
&lt;/tt&gt;      onComplete: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request){&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.completeAjaxRequest(request);&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; (finishMethod) { finishMethod.&lt;span class=&quot;fu&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;,request) };&lt;tt&gt;
&lt;/tt&gt;      }.bind(&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;),&lt;tt&gt;
&lt;/tt&gt;      parameters: parameters.merge(authParams),&lt;tt&gt;
&lt;/tt&gt;      method: method&lt;tt&gt;
&lt;/tt&gt;    });&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;




&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul class=&quot;mt20&quot;&gt;
  &lt;li&gt;The Latest HomeMarks &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/master/public/javascripts/homemarks/app.js&quot; class=&quot;external-link&quot;&gt;app.js&lt;/a&gt; Class. See doAjaxRequest() function.&lt;/li&gt;
&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-05-30:147</id>
    <published>2008-05-30T03:21:00Z</published>
    <updated>2008-05-30T12:44:55Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="Workflow"/>
    <category term="bdd"/>
    <category term="rails"/>
    <category term="shoulda"/>
    <category term="tdd"/>
    <category term="testing"/>
    <link href="http://www.metaskills.net/2008/5/30/coulda-shoulda-woulda" rel="alternate" type="text/html"/>
    <title>Coulda Shoulda Woulda</title>
<summary type="html">&lt;p&gt;
  It has been about 6 months now since I started using the &lt;a href=&quot;http://www.thoughtbot.com/projects/shoulda&quot; class=&quot;external-link&quot;&gt;Shoulda&lt;/a&gt; testing plugin as my BDD/TDD tool of choice. Unlike a lot of other people, I did not flock to the RSpec bandwaggon. Personally I think RSpec is horribly bloated a sledgehammer for a simple issue, the need to have test code organized with nested setups and context blocks.
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;
  It has been about 6 months now since I started using the &lt;a href=&quot;http://www.thoughtbot.com/projects/shoulda&quot; class=&quot;external-link&quot;&gt;Shoulda&lt;/a&gt; testing plugin as my BDD/TDD tool of choice. Unlike a lot of other people, I did not flock to the RSpec bandwaggon. Personally I think RSpec is horribly bloated a sledgehammer for a simple issue, the need to have test code organized with nested setups and context blocks.
&lt;/p&gt;
&lt;p&gt;
  It has been about 6 months now since I started using the &lt;a href=&quot;http://www.thoughtbot.com/projects/shoulda&quot; class=&quot;external-link&quot;&gt;Shoulda&lt;/a&gt; testing plugin as my BDD/TDD tool of choice. Unlike a lot of other people, I did not flock to the RSpec bandwaggon. Personally I think RSpec is horribly bloated a sledgehammer for a simple issue, the need to have test code organized with nested setups and context blocks.
&lt;/p&gt;

&lt;p&gt;
  If you are new to Shoulda, I highly urge you to take a look at the &lt;a href=&quot;http://www.thoughtbot.com/projects/shoulda&quot; class=&quot;external-link&quot;&gt;Thoughbot project page&lt;/a&gt; for it. If you have the time take a look at some of their other projects, like Paperclip. These guys are really smart. If you really want to see how shoulda can sing, check out &lt;a href=&quot;http://mwrc2008.confreaks.com/12saleh.html&quot; class=&quot;external-link&quot;&gt;Tammer Saleh's presentation of it at the MountainWest RubyConf 2008&lt;/a&gt;. In that presentation he covers how you can extend Shoulda and write your own macros that generate additional tests. This is what my blog post is about.
&lt;/p&gt;


&lt;h2&gt;Sample Shoulda Macro For Functional Require Login&lt;/h2&gt;

&lt;p&gt;
  Here is a simple module that you might find for any restful authentication system. This would be included in your main &lt;code&gt;test_helper.rb&lt;/code&gt; file where it would add the normal login_as(user) method. The good part I want to point out is the &lt;code&gt;should_require_login(*actions)&lt;/code&gt; macro method that shows off a neat example of how you could use Shoulda in your functional tests at the class level.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;AuthSystem&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;TestHelper&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.included(receiver)&lt;tt&gt;
&lt;/tt&gt;      receiver.extend &lt;span class=&quot;co&quot;&gt;ClassMethods&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      receiver.send &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;InstanceMethods&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;ClassMethods&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;should_require_login&lt;/span&gt;(*actions)&lt;tt&gt;
&lt;/tt&gt;        actions.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |action|&lt;tt&gt;
&lt;/tt&gt;          should &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Require login for '&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;action&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;' action&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            get(action)&lt;tt&gt;
&lt;/tt&gt;            assert_redirected_to(login_url)&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;InstanceMethods&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;login_as&lt;/span&gt;(user)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; u = users(user)&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;iv&quot;&gt;@request&lt;/span&gt;.session[&lt;span class=&quot;sy&quot;&gt;:user_id&lt;/span&gt;] = u.id&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;
  Here is how it would look in the controller functional test. These are all contrived examples, but I think it illustrates how Shoulda can be used and in general how you can make your own macros that test at a higher level.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;UsersControllerTest&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActionController&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;TestCase&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  should_require_login &lt;span class=&quot;sy&quot;&gt;:edit&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:update&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:etc&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-05-24:136</id>
    <published>2008-05-24T20:00:00Z</published>
    <updated>2008-05-30T12:48:44Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="ajax"/>
    <category term="design"/>
    <category term="javascript"/>
    <category term="pattern"/>
    <category term="unobtrusive"/>
    <link href="http://www.metaskills.net/2008/5/24/the-ajax-head-br-design-pattern" rel="alternate" type="text/html"/>
    <title>The "AJAX Head" Design Pattern</title>
<summary type="html">&lt;p&gt;
  This is the first of a few articles covering the total rewrite of the &lt;a href=&quot;http://homemarks.com/&quot; class=&quot;external-link&quot;&gt;HomeMarks.com&lt;/a&gt; code base as I upgrade it to Rails 2.1. The &quot;AJAX Head&quot; pattern is the moniker I have assigned to methodology that has come about during said rewrite and the design decisions I choose early on. The rules were simple...
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;
  This is the first of a few articles covering the total rewrite of the &lt;a href=&quot;http://homemarks.com/&quot; class=&quot;external-link&quot;&gt;HomeMarks.com&lt;/a&gt; code base as I upgrade it to Rails 2.1. The &quot;AJAX Head&quot; pattern is the moniker I have assigned to methodology that has come about during said rewrite and the design decisions I choose early on. The rules were simple...
&lt;/p&gt;


&lt;p&gt;
  This is the first of a few articles covering the total rewrite of the &lt;a href=&quot;http://homemarks.com/&quot; class=&quot;external-link&quot;&gt;HomeMarks.com&lt;/a&gt; code base as I upgrade it to Rails 2.1. The &quot;AJAX Head&quot; pattern is the moniker I have assigned to methodology that has come about during said rewrite and the design decisions I choose early on. The rules were simple.
&lt;/p&gt;

&lt;ul class=&quot;mt20&quot;&gt;
  &lt;li&gt;Total Unobtrusive JavaScript (&lt;a href=&quot;http://en.wikipedia.org/wiki/Tag_soup&quot; class=&quot;external-link&quot;&gt;No Tag Soup&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;No RJS Controller Responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  Rails makes it very easy to generate JavaScript with Ruby. The generator methods are extensive and cover both the Prototype and Scriptaculous libraries. The first version of HomeMarks used the generators exclusively to augment both the views and controller responses. In fact, I used a technique that is covered in the latest &lt;a href=&quot;http://www.pragprog.com/titles/fr_arr/advanced-rails-recipes&quot; class=&quot;external-link&quot;&gt;&lt;em&gt;Advanced Rails Recipes&lt;/em&gt;&lt;/a&gt; (way before it came out) under the &quot;Replace In-View Raw JavaScript&quot; chapter. Basically I created helper methods that generated JavaScript shared by both the views and controllers. It was a great technique but things &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/d33dab1405537db2d2dab86d79db415d9e7f56e5/app/helpers/application_helper.rb&quot; class=&quot;external-link&quot;&gt;got messy quick&lt;/a&gt;. So life was good back then, I had a lot of Ruby code and a very dynamic site, but something did not seem right...
&lt;/p&gt;

&lt;h2&gt;What Is The AJAX Head Pattern?&lt;/h2&gt;

&lt;p&gt;
  It is an experiment into a vision to see what happens when you make the decision to totally go unobtrusive. Not just in your views but the controllers too! Imagine it this way &amp;mdash; your controllers are &lt;strong&gt;slim APIs&lt;/strong&gt;. They should do nothing but render a page on a GET request and when it comes to a POST/PUT/DELETE they should do nothing more than just say YES or NO (with errors).
&lt;/p&gt;

&lt;p&gt;
  Now lets think about that. What does that mean for an application that uses exclusive AJAX calls for dynamic page updates? It means that your visual client (the browser) will need to know ALOT less from the controller about what to do. It's great, the browser knows what is on the page, from the GET request, and what it needs to do with it. The client only needs to tell the remote resource store what it did. In this pattern the controller is relegated to nothing more than acting on model data and letting the client know if it succeeded or failed. So in short.
&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div&gt;
    The AJAX head design pattern forces the view and controller to work in isolation with the most minimal coupling possible. Kind of like a web service.
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;h2&gt;Tools and Code Needed&lt;/h2&gt;

&lt;ul class=&quot;mt20&quot;&gt;
  &lt;li&gt;A application that does just about everything with AJAX.&lt;/li&gt;
  &lt;li&gt;Fluency with ActionController::Base#head method and HTTP status codes.&lt;/li&gt;
  &lt;li&gt;Site-wide exception rescues for ActiveRecord::RecordInvalid.&lt;/li&gt;
  &lt;li&gt;Global client-side AJAX request and response handlers.&lt;/li&gt;
  &lt;li&gt;Global client-side error handlers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  This may seem like a daunting list, but its pretty simple when you break it down. Let's do each one at at time with some of the current code from HomeMarks. The HomeMarks app is my first check on the list. When I did this app just about EVERYTHING was done via an AJAX call to update the page. Now on to the others.
&lt;/p&gt;


&lt;h2&gt;2) Head And Status Codes&lt;/h2&gt;

&lt;p&gt;
  The &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/Base.html#M000454&quot; class=&quot;external-link&quot;&gt;ActionController::Base#head&lt;/a&gt; method and &lt;a href=&quot;http://dev.rubyonrails.org/browser/trunk/actionpack/lib/action_controller/status_codes.rb&quot; class=&quot;external-link&quot;&gt;HTTP status codes&lt;/a&gt; are the second item on the list. The head method is very useful when you just want to respond with HTTP headers and no body content. This is typical behavior when an app responds to external web services requests. This is important to note, I chose to rely on head responses as a way to meet my design decision of not using any RJS responses from the controller.
&lt;/p&gt;
  
  
&lt;p&gt;
  The basic usage of the head method is simple, you just pass a symbol to the head method that is the lowercase underscore equivalent to an HTTP status code. For instance, if you wanted to respond with success, choose a status code from the 200 range, the easiest being 'OK', which would look like &lt;code&gt;head(:ok)&lt;/code&gt;. If you wanted to respond to bad authentication, you might use the 401 code like so, &lt;code&gt;head(:unauthorized)&lt;/code&gt;. Here is an example from HomeMarks restful user signup action.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;UsersController&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ApplicationController&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;# ...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;create&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;co&quot;&gt;User&lt;/span&gt;.create!(params[&lt;span class=&quot;sy&quot;&gt;:user&lt;/span&gt;])&lt;tt&gt;
&lt;/tt&gt;    head &lt;span class=&quot;sy&quot;&gt;:ok&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;# ...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;
  There is actually a number of things going on in those 2 lines of code above. If the user is created, the AJAX request will get a simple 'OK' message via the head method. Obviously the client will need to know what to do on its own. But if errors happen what to do? This brings us to...
&lt;/p&gt;


&lt;h2&gt;3) Invalid Object Handling&lt;/h2&gt;

&lt;p&gt;
  When Rails 2 came out, it gave us a very useful tool for our controllers, the &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/Rescue/ClassMethods.html&quot; class=&quot;external-link&quot;&gt;ActionController#rescue_from&lt;/a&gt; method. It allows you to delegate exception handling to a method either per controller or site wide for a specific exception class. So enter the &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/master/lib/render_invalid_record.rb&quot; class=&quot;external-link&quot;&gt;RenderInvalidRecord&lt;/a&gt; module, show below.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;RenderInvalidRecord&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.included(base)&lt;tt&gt;
&lt;/tt&gt;    base.rescue_from(&lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;RecordInvalid&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:with&lt;/span&gt; =&amp;gt; &lt;span class=&quot;sy&quot;&gt;:render_invalid_record&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  protected&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;render_invalid_record&lt;/span&gt;(exception)&lt;tt&gt;
&lt;/tt&gt;    record = exception.record&lt;tt&gt;
&lt;/tt&gt;    respond_to &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |format|&lt;tt&gt;
&lt;/tt&gt;      format.html { render &lt;span class=&quot;sy&quot;&gt;:action&lt;/span&gt; =&amp;gt; (record.new_record? ? &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) }&lt;tt&gt;
&lt;/tt&gt;      format.js   { render &lt;span class=&quot;sy&quot;&gt;:json&lt;/span&gt; =&amp;gt; record.errors.full_messages, &lt;span class=&quot;sy&quot;&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class=&quot;sy&quot;&gt;:unprocessable_entity&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:content_type&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;      format.xml  { render &lt;span class=&quot;sy&quot;&gt;:xml&lt;/span&gt; =&amp;gt; record.errors.full_messages,  &lt;span class=&quot;sy&quot;&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class=&quot;sy&quot;&gt;:unprocessable_entity&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;      format.json { render &lt;span class=&quot;sy&quot;&gt;:json&lt;/span&gt; =&amp;gt; record.errors.full_messages, &lt;span class=&quot;sy&quot;&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class=&quot;sy&quot;&gt;:unprocessable_entity&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;
  Once included in your application.rb file, every ActiveRecord::RecordInvalid exception will be handled by the render_invalid_record method. I use this pattern often and it is the primary reason I always use the &lt;strong&gt;bang methods&lt;/strong&gt; that end with an exclamation point, such as &lt;code&gt;create!&lt;/code&gt; or &lt;code&gt;save!&lt;/code&gt;. This module above was inspired by &lt;a href=&quot;http://github.com/josh/&quot; class=&quot;external-link&quot;&gt;Joshua Peek's&lt;/a&gt; own module of the same name but has been edited here to fit my needs. Both the &quot;xml&quot; and &quot;html&quot; response formats are not used by HomeMarks but are included here to show how this module can work for any request type.
&lt;/p&gt;

&lt;p&gt;
  Now, how this fits into the AJAX Head pattern. The design decision of not having RJS responses means one of two things needs to come from the response. First, if the response is a success, meaning in the 200 range, then it is assumed that the client only needs to know that all is 'OK'. Second, if the request has errors, then the response needs to communicate them. I choose JSON for the format of these errors since all AJAX request objects from Prototype automatically include a &lt;code&gt;application/json&lt;/code&gt; accept header. So that is why I changed both the &quot;js&quot; and the &quot;json&quot; response type in the RenderInvalidRecord module to both serialize the objects full error messages into a JSON array with an HTTP status code of 422 &quot;Unprocessable Entity&quot; which seemed to make the most sense to me. This pretty much wraps up the server side part of the pattern. Now onto the client side. Everything from here on is personal taste on how your client will react to an &quot;good&quot; or &quot;bad&quot; response object.
&lt;/p&gt;


&lt;h2&gt;4) Client-Side AJAX Handlers&lt;/h2&gt;

&lt;p&gt;
  I can not stress enough how much you have to bake your own functions to handle the client side reaction to both good and bad AJAX responses. The client's ability to know what to do with errors will be tightly coupled to AJAX handlers and the design choices of your site. In the examples below I have broken up methods in the same JavaScript classes to show you the parts for a specific behavior in a more concise manner. Also please note that I am using Prototype module and class organization heavily in HomeMarks. This allows me to build a Base JavaScript module and classes that mimic Rails models which inherit/mixin Base methods. I also use the Scriptaculous Builder class for creating DOM fragments too. Now back to business.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;http://metaskills.net/files/homemarksv2/signup.html&quot; title=&quot;HomeMarks v2 Signup&quot;&gt;&lt;img class=&quot;floatr&quot; src=&quot;http://metaskills.net/files/homemarksv2/preview_signup2.png&quot; height=&quot;251&quot; width=&quot;246&quot;&gt;&lt;/a&gt;The first part of the AJAX head pattern was to use unobtrusive JavaScript. Because of this design choice, there are no &lt;code&gt;remote_form_for&lt;/code&gt; methods in the HomeMarks view code. All forms are simple &lt;code&gt;form_for&lt;/code&gt; methods. Below is a sample of the HomeMarksSite JavaScript class that creates AJAX handlers for all site forms. The below example is slimmed down to only show the initialization of this behavior for the signup form. But no matter which form is given this behavior the process is the same.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The form's submit event is handled by &lt;code&gt;startAjaxForm()&lt;/code&gt;. It does the following:&lt;/li&gt;
    &lt;ul&gt;
      &lt;li&gt;Stops the normal submit behavior.&lt;/li&gt;
      &lt;li&gt;Adds a loading spinner in the #form_loading span.&lt;/li&gt;
      &lt;li&gt;Creates a new AJAX.Request using the forms own action. It also binds a function to delegate the logic of completing the form when the request is finished. More on that later in #2 below.&lt;/li&gt;
      &lt;li&gt;Finally it disables the form.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;li&gt;Once a response comes back from the server, the &lt;code&gt;delegateCompleteAjaxForm()&lt;/code&gt; function will be called with both the form object and the AJAX request object. The logic of this function includes:&lt;/li&gt;
  &lt;ul&gt;
    &lt;li&gt;Figuring out the &quot;mood&quot; of the request using getRequestMood() function which is part of my base module.&lt;/li&gt;
    &lt;li&gt;Sends the form and mood to the &lt;code&gt;completeAjaxForm()&lt;/code&gt; function. This function will replace the loading spinner with an image that reflects a good or bad response.&lt;/li&gt;
    &lt;li&gt;If the mood is good, meaning the response status code was within a 200 range, then the function will delegate to a function specific for that forms success using a simple case statement.&lt;/li&gt;
    &lt;li&gt;If this mood is bad, meaning the response status code not within a 200 range, the form will be enabled and the response JSON errors will be displayed. Currently I am using a modal class for this. Again more on that later. You may also note that my base module has a function called &lt;code&gt;messagesToList()&lt;/code&gt; that process the response into a DOM &amp;lt;ul&amp;gt; list.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/ul&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; HomeMarksBase = {&lt;tt&gt;
&lt;/tt&gt;  getRequestMood: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; (request.status &amp;gt;= 200 &amp;amp;&amp;amp; request.status &amp;lt; 300) ? &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;good&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;bad&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  messagesToList: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; messages = request.responseJSON;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; messageList = UL();&lt;tt&gt;
&lt;/tt&gt;    messages.each(&lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(message){ &lt;tt&gt;
&lt;/tt&gt;      messageList.appendChild( LI(message.escapeHTML()) );&lt;tt&gt;
&lt;/tt&gt;    });&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; messageList;&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;};&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; HomeMarksSite = Class.create(HomeMarksBase,{ &lt;tt&gt;
&lt;/tt&gt;  initialize: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.signupForm = $(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;signup_form&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.initEvents();&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  startAjaxForm: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;pt&quot;&gt;event&lt;/span&gt;) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pt&quot;&gt;event&lt;/span&gt;.&lt;span class=&quot;fu&quot;&gt;stop&lt;/span&gt;();&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; form = &lt;span class=&quot;pt&quot;&gt;event&lt;/span&gt;.findElement(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; options = &lt;span class=&quot;pt&quot;&gt;Object&lt;/span&gt;.extend({imgSrc:&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;loading_invert.gif&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}, arguments[1] || {});&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; loadArea = form.down(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#form_loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; imgTag = IMG({src:(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/images/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;+options.imgSrc)});&lt;tt&gt;
&lt;/tt&gt;    $(loadArea).update(imgTag);&lt;tt&gt;
&lt;/tt&gt;    new Ajax.Request(form.action,{&lt;tt&gt;
&lt;/tt&gt;      onComplete: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request){ &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.delegateCompleteAjaxForm(form,request) }.bind(&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;),&lt;tt&gt;
&lt;/tt&gt;      parameters: form.serialize(&lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    });&lt;tt&gt;
&lt;/tt&gt;    form.disable();&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  delegateCompleteAjaxForm: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(form,request) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; mood = &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.getRequestMood(request);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.completeAjaxForm(form,{mood:mood});&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; (mood == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;good&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) { &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;switch&lt;/span&gt; (form) { &lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.supportForm : &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.completeSupportForm(request); &lt;span class=&quot;r&quot;&gt;break&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;      }&lt;tt&gt;
&lt;/tt&gt;    }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;else&lt;/span&gt; { &lt;tt&gt;
&lt;/tt&gt;      form.enable();&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; (!request.responseText.blank()) {&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; flashHTML = DIV([H2(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Errors On Form!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;),&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.messagesToList(request)]);&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flashModal(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;bad&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;,flashHTML);&lt;tt&gt;
&lt;/tt&gt;      };&lt;tt&gt;
&lt;/tt&gt;    };&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  completeAjaxForm: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(form) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; options = &lt;span class=&quot;pt&quot;&gt;Object&lt;/span&gt;.extend({mood:&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;good&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}, arguments[1] || {});&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; loadArea = form.down(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#form_loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; completeId = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;complete_ajax_form_&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; + form.id;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; imgSrc = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/images/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;+options.mood+&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; moodHtml = SPAN({id:completeId,className:&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;m0 p0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}, [IMG({src:imgSrc})]);&lt;tt&gt;
&lt;/tt&gt;    $(loadArea).update(moodHtml);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;fu&quot;&gt;setTimeout&lt;/span&gt;(&lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() { $(completeId).fade(); },3000);&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  completeSignupForm: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; message = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Thank your for signing up for your own HomeMarks page. An email has been sent to &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;your address along with a link to activate your account. If you have not done so already, please &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;take a moment to read the HomeMarks documentation.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; flashHTML = DIV([H2(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Signup Complete:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;),P(message)]);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flash(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;good&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;,flashHTML);&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  initEvents: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.signupForm) { &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.signupForm.observe(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.startAjaxForm.bindAsEventListener(&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;)); };&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;});&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;



&lt;h2&gt;5) Client-Side Error Handling&lt;/h2&gt;

&lt;p&gt;
  Currently I have 3 client-side options that I can use to present errors back to the user from the JSON array in AJAX response. The first I started out with was using the &lt;code&gt;alert()&lt;/code&gt; function. That got boring real quick, but I left my implementation below which is part of the base class, called &lt;code&gt;messagesToAlert()&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
  The second slightly more interesting way was to create a flash message that used the same XHTML/CSS already present in my layout file. This was real easy to implement. Basically using the ERB fragment below in my layout, I guaranteed that I had 3 unique DOM elements for each of my flash message styles, good/bad/indif. Now all I had to do was to create an accessor in my HomeMarksSite class. I choose &lt;code&gt;this.flashes&lt;/code&gt;. I then created a &lt;code&gt;clearFlashes()&lt;/code&gt; function and then a &lt;code&gt;flash()&lt;/code&gt; function that would take the mood and the HTML to embed, viola – I can now call &lt;code&gt;this.flash.('good',someHTML)&lt;/code&gt; and I get the same type of flash one would have seen if I set it in the controller and rendered. Note, this is what I used on the the signup form success above.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;% [&lt;span class=&quot;sy&quot;&gt;:good&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:bad&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:indif&lt;/span&gt;].each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |key| &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;div id=&amp;quot;flash_&amp;lt;%= key %&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; class=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;flash_message&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; style=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;display&lt;span class=&quot;sy&quot;&gt;:&amp;lt;&lt;/span&gt;%= flash[key].blank? ? &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;;&amp;quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &amp;lt;span&amp;gt;&amp;lt;%= flash[key] &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&amp;lt;/span&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;div&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;% end %&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; HomeMarksBase = {&lt;tt&gt;
&lt;/tt&gt;  messagesToAlert: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; messages = request.responseJSON;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; alertText = messages.&lt;span class=&quot;fu&quot;&gt;join&lt;/span&gt;(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; (alertText.endsWith(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)) { &lt;span class=&quot;fu&quot;&gt;alert&lt;/span&gt;(alertText); } &lt;span class=&quot;r&quot;&gt;else&lt;/span&gt; { &lt;span class=&quot;fu&quot;&gt;alert&lt;/span&gt;(alertText+&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;); };&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  messagesToList: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(request) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; messages = request.responseJSON;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; messageList = UL();&lt;tt&gt;
&lt;/tt&gt;    messages.each(&lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(message){ &lt;tt&gt;
&lt;/tt&gt;      messageList.appendChild( LI(message.escapeHTML()) );&lt;tt&gt;
&lt;/tt&gt;    });&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; messageList;&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;};&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; HomeMarksSite = Class.create(HomeMarksBase,{ &lt;tt&gt;
&lt;/tt&gt;  initialize: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flashes = $$(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;div.flash_message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  clearFlashes: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flashes.invoke(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;hide&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flashes.invoke(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;  flash: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(mood,html) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.clearFlashes();&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; moodFlash = &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flashes.&lt;span class=&quot;fu&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(e){ &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; (e.id == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;flash_&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;+mood) {&lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;}; });&lt;tt&gt;
&lt;/tt&gt;    moodFlash.update(html);&lt;tt&gt;
&lt;/tt&gt;    moodFlash.show();&lt;tt&gt;
&lt;/tt&gt;    $(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;site_wrapper&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).&lt;span class=&quot;fu&quot;&gt;scrollTo&lt;/span&gt;();&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;});&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;
  &lt;a href=&quot;http://metaskills.net/files/homemarksv2/login.html&quot; title=&quot;HomeMarks v2 Login&quot;&gt;&lt;img class=&quot;floatr&quot; src=&quot;http://metaskills.net/files/homemarksv2/preview_login2.png&quot; height=&quot;251&quot; width=&quot;246&quot;&gt;&lt;/a&gt;Lastly, and probably the coolest, is the HomeMarksModal JavaScript class I created. This is my new default way of errors to a user. It can be seen in all my video examples on this page. To the right is another example of the login form that uses the same handlers described above. The HomeMarksModal JavaScript class is a bit large to paste inline in this article, but if you want to see the latest version, you can always get it &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/master/public/javascripts/homemarks/modal.js&quot; class=&quot;external-link&quot;&gt;from the master branch of the homemarks_core project&lt;/a&gt; on Github.com. When you bind an instance of this object to the window/document, it will automatically crate the modal HTML using Builder. If you want to use it, make sure to get the CSS and images the project too. Below is a function that I put in my site class that allows me to call &lt;code&gt;this.flashModal('good',someHTML))&lt;/code&gt;.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; HomeMarksSite = Class.create(HomeMarksBase,{ &lt;tt&gt;
&lt;/tt&gt;  flashModal: &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;(mood,html) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; moodColor = &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.flashMoodColors.get(mood);&lt;tt&gt;
&lt;/tt&gt;    HmModal.show(html,{color:moodColor});&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;});&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;



&lt;h2&gt;Wrapping It Up&lt;/h2&gt;

&lt;p&gt;
  This article turned out a lot longer than I had wanted. The AJAX head pattern is pretty simple and it is really fun to see a two line user signup action yield such interactive results. Something also feels good about not putting view code in the controller, yes you can look at inline RJS as view code. Sure it requires that you do a lot more JS work, but there are benefits.
&lt;/p&gt;

&lt;p&gt;
  Image you have team of programmers, one person can stay in model/controller land while the other stays on the view/javascript. The model/controller person would write their own tests (PLEASE TAKE A LOOK AT MINE), while the view/javascript person might even take the initiative to use selenium to test the JavaScript. At the time of this writing, I have not done any selenium tests since the plugin for rails is not compatible for 2.0. That last benefit I could think of for this design pattern is that you could easily update view code without restarting your rails app. Just update the JavaScripts and your good to go.
&lt;/p&gt;

&lt;p&gt;
  In closing, please let me know what you think. Perhaps you have a better name for the design pattern? Perhaps someone else has a name for it already?
&lt;/p&gt;



&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul class=&quot;mt20&quot;&gt;
  &lt;li&gt;Original &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/d33dab1405537db2d2dab86d79db415d9e7f56e5/app/helpers/application_helper.rb&quot; class=&quot;external-link&quot;&gt;application_helper.rb&lt;/a&gt; from HomeMarks v1. An overboard example of shared view/controller tagsoup/rjs.&lt;/li&gt;
  &lt;li&gt;The latest &lt;a href=&quot;http://www.pragprog.com/titles/fr_arr/advanced-rails-recipes&quot; class=&quot;external-link&quot;&gt;&lt;em&gt;Advanced Rails Recipes&lt;/em&gt;&lt;/a&gt; book. See the chapter on &quot;Replace In-View Raw JavaScript&quot;. I discourage this technique used in mass.&lt;/li&gt;
  &lt;li&gt;Rails API for the &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/Base.html#M000454&quot; class=&quot;external-link&quot;&gt;ActionController::Base#head&lt;/a&gt; method.&lt;/li&gt;
  &lt;li&gt;Rails API for the &lt;a href=&quot;http://dev.rubyonrails.org/browser/trunk/actionpack/lib/action_controller/status_codes.rb&quot; class=&quot;external-link&quot;&gt;HTTP status codes&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Rails API for the &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/Rescue/ClassMethods.html&quot; class=&quot;external-link&quot;&gt;ActionController#rescue_from&lt;/a&gt; method.&lt;/li&gt;
  &lt;li&gt;The latest &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/master/lib/render_invalid_record.rb&quot; class=&quot;external-link&quot;&gt;RenderInvalidRecord&lt;/a&gt; module from the HomeMarks core.&lt;/li&gt;
  &lt;li&gt;The latest  &lt;a href=&quot;http://github.com/metaskills/homemarks/tree/master/public/javascripts/homemarks/modal.js&quot; class=&quot;external-link&quot;&gt;HomeMarksModal&lt;/a&gt; JavaScript class from the HomeMarks core.&lt;/li&gt;
&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-25:132</id>
    <published>2008-04-25T14:34:00Z</published>
    <updated>2008-05-24T01:46:13Z</updated>
    <category term="Apple/OSX"/>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="TextMate"/>
    <category term="apple"/>
    <category term="environment"/>
    <category term="path"/>
    <category term="ruby"/>
    <category term="rubyamp"/>
    <category term="textmate"/>
    <link href="http://www.metaskills.net/2008/4/25/using-rubyamp-textmate-bundle-with-opt-ruby" rel="alternate" type="text/html"/>
    <title>Using RubyAMP TextMate Bundle With /opt Ruby</title>
<summary type="html">&lt;p&gt;I've been a TextMate user for a long time now and I'm still finding new things to do with it. Here recently I wanted to use the &lt;a href=&quot;http://code.leadmediapartners.com/tools/rubyamp&quot; class=&quot;external-link&quot;&gt;RubyAMP TextMate Bundle&lt;/a&gt; and was a little miffed to find that it was pointing to my OS X system ruby. The error message looked something like this when it went looking for my ruby/gems.&lt;/p&gt;

&lt;pre&gt;
No such file to load -- appscript (LoadError) from 
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `require’
...
&lt;/pre&gt;</summary><content type="html">
            &lt;p&gt;I've been a TextMate user for a long time now and I'm still finding new things to do with it. Here recently I wanted to use the &lt;a href=&quot;http://code.leadmediapartners.com/tools/rubyamp&quot; class=&quot;external-link&quot;&gt;RubyAMP TextMate Bundle&lt;/a&gt; and was a little miffed to find that it was pointing to my OS X system ruby. The error message looked something like this when it went looking for my ruby/gems.&lt;/p&gt;

&lt;pre&gt;
No such file to load -- appscript (LoadError) from 
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `require’
...
&lt;/pre&gt;
&lt;p&gt;I've been a TextMate user for a long time now and I'm still finding new things to do with it. Here recently I wanted to use the &lt;a href=&quot;http://code.leadmediapartners.com/tools/rubyamp&quot; class=&quot;external-link&quot;&gt;RubyAMP TextMate Bundle&lt;/a&gt; and was a little miffed to find that it was pointing to my OS X system ruby. The error message looked something like this when it went looking for my ruby/gems.&lt;/p&gt;

&lt;pre&gt;
No such file to load -- appscript (LoadError) from 
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `require’
...
&lt;/pre&gt;

&lt;p&gt;My problem is that I use ruby installed from MacPorts (yes I have Leopard). I do this because I put a lot of crap and extra dependencies into my opt direcotry and I do not trust Apple to NOT blow away the crazy dependencey hell I would have ended up creating in the standard bin directories if I chose not to use MacPorts. I would have thought that my &lt;code&gt;TM_RUBY&lt;/code&gt; environment variable being set correctly to &lt;code&gt;/opt/local/bin/ruby&lt;/code&gt; in my TextMate preferences would have given RubyAMP enough info to find my correct gem environment. Obviously not... and it took me quite a bit of digging around to learn what else I needed to do. For starters, here is more than you ever wanted to know about &lt;a href=&quot;http://macromates.com/textmate/manual/shell_commands#search_path&quot; class=&quot;external-link&quot;&gt;how TextMate gets the $PATH information&lt;/a&gt;. You can skip reading that and do these simple steps.&lt;/p&gt;

&lt;ul class=&quot;mt10&quot;&gt;
&lt;li&gt;Open /Developer/Applications/Utilities/Property List Editor.app&lt;/li&gt;
&lt;li&gt;Click on &quot;New Root&quot;, now expand that node in the list view below.&lt;/li&gt;
&lt;li&gt;Click on &quot;New Child&quot;, name it PATH&lt;/li&gt;
&lt;li&gt;The child row for PATH should be a String type&lt;/li&gt;
&lt;li&gt;Enter your PATH info here, should mimic your .bash_profile, without $PATH&lt;/li&gt;
&lt;li&gt;Save this file to your Desktop as environment.plist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now do this in the console, we need to move that file to an invisible &lt;code&gt;.MacOSX&lt;/code&gt; folder in your home directory. In all likelyhood this folder does not exists, nor does the environment.plist file inside of it, if so, please do your own work to make sure that you do not overwrite existing information. Now:&lt;/p&gt;

&lt;pre class=&quot;command&quot;&gt;
mkdir ~/.MacOSX
mv ~/Desktop/environment.plist ~/.MacOSX
&lt;/pre&gt;

&lt;p&gt;With the file in place, you now have to log out and back in. To be on the safe side, just reboot. Now your OSX apps, including TextMate and it's bundles will have the correct PATH information to get to your binaries. See below for an example of what my environment.plist file looks like. Note too that my full PATH info in that file is this string &lt;code&gt;/opt/local/bin:/opt/local/sbin:/opt/local/lib/mysql5/bin:/opt/local/apache2/bin&lt;/code&gt;. Notice that path info after the apache2 path? This is where you should add the default path info for a Mac. Unlike the .bash_profile, you can not specify &lt;code&gt;$PATH&lt;/code&gt; and have it expanded from within a plist file. So to be on the safe side, when I added this, I put the standard mac path info at the end of my own additions. That standard path info is &lt;code&gt;/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin&lt;/code&gt;&lt;/p&gt;



&lt;div class=&quot;iecenter&quot;&gt;
  &lt;img src=&quot;http://www.metaskills.net/assets/2008/4/25/envplist.png&quot; height=&quot;302&quot; width=&quot;496&quot; /&gt;
&lt;/div&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-22:131</id>
    <published>2008-04-22T03:12:00Z</published>
    <updated>2008-05-06T13:19:18Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="edge"/>
    <category term="mod_rails"/>
    <category term="passenger"/>
    <category term="rails"/>
    <link href="http://www.metaskills.net/2008/4/22/how-to-use-passenger-mod_rails-with-rails-edge-2-1" rel="alternate" type="text/html"/>
    <title>How to use Passenger (mod_rails) with rails edge 2.1</title>
<content type="html">
            &lt;p&gt;If you are like me and have &lt;a href=&quot;/2008/4/13/now-on-passenger-mod_rails&quot;&gt;been using passenger&lt;/a&gt;, then you may have run into an issue when working with rails edge. I mean the REAL rails edge on Git, not that fancy rake task which I think is still pointing to a subversion snapshot. Let me take an aside on how to freeze rails edge to a project that you are managing in Git. This method is akin to using svn:externals. As a cop out, here are 3 links that you should read to learn how.&lt;/p&gt;

&lt;div class=&quot;update bold iecenter mt20 mb20&quot;&gt;UPDATE: This issue has &lt;a href=&quot;http://github.com/FooBarWidget/passenger/commit/53301de464b323d364723854d3a8d293ab8327d6&quot; class=&quot;external-link&quot;&gt;now been resolved&lt;/a&gt; in the official release.&lt;/div&gt; 

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://railsontherun.com/2008/4/16/freezing-rails-with-git&quot; class=&quot;external-link&quot;&gt;http://railsontherun.com/2008/4/16/freezing-rails-with-git&lt;/a&gt;
&lt;li&gt;&lt;a href=&quot;http://woss.name/2008/04/09/using-git-submodules-to-track-vendorrails/&quot; class=&quot;external-link&quot;&gt;http://woss.name/2008/04/09/using-git-submodules-to-track-vendorrails/&lt;/a&gt;
&lt;li&gt;&lt;a href=&quot;http://git.or.cz/gitwiki/GitSubmoduleTutorial&quot; class=&quot;external-link&quot;&gt;http://git.or.cz/gitwiki/GitSubmoduleTutorial&lt;/a&gt;
&lt;/ul&gt;

&lt;p&gt;OK... now that you know how to freeze the real rails edge to your git project, and if you have been using passenger, you may now have seen this error below. The basic problem is that passenger bypasses the work that the rails boot.rb does and in doing so, it only accounts for setting RAILS_ROOT during the ApplicationSpawner process and not the FrameworkSpawner process. In the latest rails, ActionPack is now relying on RAILS_ROOT to be set by calling Rails.root (shortcut method to that constant) when loading. So &lt;a href=&quot;http://github.com/metaskills/passenger/commit/69afcd75425a89c9d17d1fc40c0a7571d6bd547c &quot; class=&quot;external-link&quot;&gt;my fix was to add the RAILS_ROOT to the FrameworkSpawner class&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;
Framework that failed to load: Vendor directory: /Users/foo/project/vendor/rails 
Error message: Anonymous modules have no name to be referenced by 
Exception class: ArgumentError 
&lt;/pre&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/phusion-passenger/issues/detail?id=29&amp;amp;can=1&amp;amp;q=edge&amp;amp;colspec=ID%20Type%20Status%20Priority%20Milestone%20Stars%20Summary&quot; class=&quot;external-link&quot;&gt;Here is the Passenger Ticket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/FooBarWidget/passenger/commit/53301de464b323d364723854d3a8d293ab8327d6&quot; class=&quot;external-link&quot;&gt;The official Passenger change set that fixed this issue.&lt;/a&gt;&lt;/li&gt;
&lt;ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-13:130</id>
    <published>2008-04-13T18:15:00Z</published>
    <updated>2008-04-14T13:10:52Z</updated>
    <category term="Apple/OSX"/>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <link href="http://www.metaskills.net/2008/4/13/now-on-passenger-mod_rails" rel="alternate" type="text/html"/>
    <title>Now on Passenger (mod_rails)</title>
<content type="html">
            &lt;div class=&quot;iecenter&quot;&gt;&lt;img src=&quot;/assets/2008/4/13/passenger_install.png&quot; height=&quot;308&quot; width=&quot;515&quot; /&gt;&lt;/div&gt;

&lt;p&gt;Well this is working out well so far. I'm really liking the &lt;a href=&quot;http://modrails.com/index.html&quot; class=&quot;external-link&quot;&gt;Passenger (mod_rails for Apache)&lt;/a&gt; extension. Right now I have this Mephisto site running it and it seems to be doing really well. Also, most people do not do this, but I run a full development stack Apache/MongrelCluster to mimic production boxes the best way I can. Now I am running mod_rails on all my development hosts.&lt;/p&gt;

&lt;h2&gt;Some Things I Like&lt;/h2&gt;

&lt;ul class=&quot;mt10&quot;&gt;
  &lt;li&gt;I do not have to fuss with OS X launchd startup scripts for my mongrels, just Apache.&lt;/li&gt;
  &lt;li&gt;Typically in a high volume site that runs mongrel behind an Apache proxy balancer, will get a large timeout and proxy error even if the mongrels are immediately available. Passenger has a &lt;a href=&quot;http://modrails.com/documentation/Users%20guide.html#_redeploying_restarting_the_ruby_on_rails_application&quot; class=&quot;external-link&quot;&gt;nice way to restart&lt;/a&gt; the app, just touch the tmp/restart.txt file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Some Things I'm Waiting For&lt;/h2&gt;

&lt;ul class=&quot;mt10&quot;&gt;
  &lt;li&gt;The RailsEnv can not be set per virtual host. You have to set RAILS_ENV = 'development' in each app if you want to run mixed virtual hosts with different environments.&lt;/li&gt;
  &lt;li&gt;Normally I would pass environment variables to the console when issuing mongrel cluster starts. I would really love to see Passenger support &lt;a href=&quot;http://httpd.apache.org/docs/2.2/env.html&quot; class=&quot;external-link&quot;&gt;apache environment variables.&lt;/li&gt;
&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-06:127</id>
    <published>2008-04-06T19:11:00Z</published>
    <updated>2008-04-16T22:30:11Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <link href="http://www.metaskills.net/2008/4/6/autotest-playlist-for-red-green-feedback" rel="alternate" type="text/html"/>
    <title>Autotest Playlist For Red/Green Feedback</title>
<summary type="html">&lt;p&gt;Here is how to get a playlist of sounds that will be hooked to both your autotest :red and :green callbacks. Basically this gives you a folder of sounds that are played one after another, in a loop, as your tests pass or fail. See this move below for a quick example.&lt;/p&gt;

&lt;div class=&quot;iecenter mt10&quot;&gt;&amp;lt;object height=&quot;350&quot; width=&quot;425&quot;&gt; &amp;lt;param&gt; &amp;lt;/param&gt; &amp;lt;embed src=&quot;http://www.youtube.com/v/HV_drKDclFA&quot; height=&quot;350&quot; width=&quot;425&quot;&gt; &amp;lt;/embed&gt; &amp;lt;/object&gt;&lt;/div&gt;</summary><content type="html">
            &lt;p&gt;Here is how to get a playlist of sounds that will be hooked to both your autotest :red and :green callbacks. Basically this gives you a folder of sounds that are played one after another, in a loop, as your tests pass or fail. See this move below for a quick example.&lt;/p&gt;

&lt;div class=&quot;iecenter mt10&quot;&gt;&amp;lt;object height=&quot;350&quot; width=&quot;425&quot;&gt; &amp;lt;param&gt; &amp;lt;/param&gt; &amp;lt;embed src=&quot;http://www.youtube.com/v/HV_drKDclFA&quot; height=&quot;350&quot; width=&quot;425&quot;&gt; &amp;lt;/embed&gt; &amp;lt;/object&gt;&lt;/div&gt;
&lt;p&gt;Here is how to get a playlist of sounds that will be hooked to both your autotest :red and :green callbacks. Basically this gives you a folder of sounds that are played one after another, in a loop, as your tests pass or fail. See this move below for a quick example.&lt;/p&gt;

&lt;div class=&quot;iecenter mt10&quot;&gt;&amp;lt;object height=&quot;350&quot; width=&quot;425&quot;&gt; &amp;lt;param&gt; &amp;lt;/param&gt; &amp;lt;embed src=&quot;http://www.youtube.com/v/HV_drKDclFA&quot; height=&quot;350&quot; width=&quot;425&quot;&gt; &amp;lt;/embed&gt; &amp;lt;/object&gt;&lt;/div&gt;

&lt;h2&gt;Step 1: Install QTPlay from MacPorts&lt;/h2&gt;

&lt;pre class=&quot;command&quot;&gt;
sudo port install qtplay
&lt;/pre&gt;

&lt;h2&gt;Step 2: Download My Autotest Playlist Files&lt;/h2&gt;

&lt;pre class=&quot;command&quot;&gt;
cd ~
curl -O http://www.metaskills.net/files/autotest_playlist.tar
tar -xf autotest_playlist.tar
mv autotest_playlist .autotest_playlist &amp;&amp; rm autotest_playlist.tar
&lt;/pre&gt;

&lt;h2&gt;Step 3: Modify Your .autotest File&lt;/h2&gt;

&lt;p&gt;User your favorite editor to open your &lt;code&gt;~/.autotest&lt;/code&gt; file. And add this code below to it. Now you should be setup to have your own playlist of sounds that play using the &lt;code&gt;qtplay&lt;/code&gt; binary installed above. If you want to play around with the sounds, then &lt;code&gt;open ~/.autotest_playlist/sounds&lt;/code&gt; and start swapping out sounds. By the way, I made the :initialize and :quit sounds using the new Alex voice in Leopard. I hijacked some text to speech and then ran an audio tool called WavePad to speed change, flange, and chorus the voice a little bit.&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;~/.autotest_playlist/playlist&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;h2&gt;Credits:&lt;/h2&gt;

&lt;p&gt;The idea for this came from &lt;a href=&quot;http://www.fozworks.com/2007/7/28/autotest-sound-effects/&quot; class=&quot;external-link&quot;&gt;FoxWorks&lt;/a&gt;. Shouts out &quot;Thank You&quot;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-06:126</id>
    <published>2008-04-06T17:52:00Z</published>
    <updated>2008-04-06T20:56:04Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="autotest"/>
    <category term="rails"/>
    <category term="ruby"/>
    <link href="http://www.metaskills.net/2008/4/6/autotest-infinite-loop-on-failure-error" rel="alternate" type="text/html"/>
    <title>Autotest Infinite Loop On Failure &amp; Error</title>
<summary type="html">&lt;p&gt;I just had an issue pop up today that seemed to be an issue for a few others. It seemed that all of a sudden that my autotest was stuck in an infinite loop after a failure or error. At first I thought it was related to some additions to my &lt;code&gt;~/.autotest&lt;/code&gt; file but after commenting out the whole lot of additions there, I realized it was something else. Here was my fix. Basically I think these errors are always related to a file that has changed during your test run. Now we just have to find out what that files are. Here are the steps I took to find out.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I just had an issue pop up today that seemed to be an issue for a few others. It seemed that all of a sudden that my autotest was stuck in an infinite loop after a failure or error. At first I thought it was related to some additions to my &lt;code&gt;~/.autotest&lt;/code&gt; file but after commenting out the whole lot of additions there, I realized it was something else. Here was my fix. Basically I think these errors are always related to a file that has changed during your test run. Now we just have to find out what that files are. Here are the steps I took to find out.&lt;/p&gt;
&lt;p&gt;I just had an issue pop up today that seemed to be an issue for a few others. It seemed that all of a sudden that my autotest was stuck in an infinite loop after a failure or error. At first I thought it was related to some additions to my &lt;code&gt;~/.autotest&lt;/code&gt; file but after commenting out the whole lot of additions there, I realized it was something else. Here was my fix. Basically I think these errors are always related to a file that has changed during your test run. Now we just have to find out what that files are. Here are the steps I took to find out.&lt;/p&gt;

&lt;h2&gt;Step 1: Gather Changed FIle Info&lt;/h2&gt;

&lt;p&gt;To find out what files are changing. To do this add the -v option when you start autotest. This will cause it to run in verbose mode. Now after you have failed a test and YOU KNOW YOU DID NOT SAVE ANYTHING watch what happens below your listing of test, assertions, failures, and errors. There will be an array dumped that will contain the files change that have caused autotest to start another test cycle. In my case here is what I saw.&lt;/p&gt;

&lt;pre class=&quot;command&quot;&gt;
1) Failure:
test_truth(BookmarkTest)
[test/unit/bookmark_test.rb:6
test/unit/bookmark_test.rb:5]:
&amp;lt;false&gt; is not true.

1 tests, 1 assertions, 1 failures, 0 errors
[[&quot;config/uuid.state&quot;, Sun Apr 06 13:58:55 -0400 2008]]
Dunno! config/uuid.state
&lt;/pre&gt;

&lt;p&gt;Ah ha... there it goes. I was using a UUID state file and it appears that file being written into the &lt;code&gt;config&lt;/code&gt; directory is the culprit. By default autotest does not ignore that directory.&lt;/p&gt;

&lt;h2&gt;Step 2: Fix The Problem&lt;/h2&gt;

&lt;p&gt;We have two options here. You can either add an autotest exception in you &lt;code&gt;~/.autotest&lt;/code&gt; file or you can bail out. My option is to bail out because I should not be adding a file at run time to the config directory. It would seem a better place would be the &lt;code&gt;tmp&lt;/code&gt; directory. However if you think that adding an exception to your &lt;code&gt;~/.autotest&lt;/code&gt; file would be more appropriate, here is the syntax&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;Autotest&lt;/span&gt;.add_hook &lt;span class=&quot;sy&quot;&gt;:initialize&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |autotest|&lt;tt&gt;
&lt;/tt&gt;  [&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.svn&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.hg&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.git&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;].each { |exception| autotest.add_exception(exception) }&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;h2&gt;Step 3
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-03:125</id>
    <published>2008-04-03T23:29:00Z</published>
    <updated>2008-04-04T13:06:31Z</updated>
    <category term="Heuristics"/>
    <category term="Ruby/Rails"/>
    <category term="actionmailer"/>
    <category term="delivery"/>
    <category term="rails"/>
    <category term="ruby"/>
    <link href="http://www.metaskills.net/2008/4/3/how-to-stop-delivery-of-an-email-within-an-actionmailer-method" rel="alternate" type="text/html"/>
    <title>How To Stop Delivery Of An Email Within An ActionMailer Method</title>
<summary type="html">&lt;p&gt;OK, so you want to keep your code placement REALLY organized. You have &lt;a href=&quot;/2008/3/26/don-t-be-a-plinko-programmer&quot;&gt;read about my persnicketyness&lt;/a&gt; and now you want to practice the best in concern placement and keep those controllers of yours really slim. Like me, you may want to try and keep controller feature additions to very specific one liners of code. Organizing your controller code to do just that with ActiveRecord models or even your own custom classes is a pretty easy task, but how do you keep things simple when dealing with controller actions that have to send email AND you want that single email link of code to be responsible for everything in it's own encapsulated way.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;OK, so you want to keep your code placement REALLY organized. You have &lt;a href=&quot;/2008/3/26/don-t-be-a-plinko-programmer&quot;&gt;read about my persnicketyness&lt;/a&gt; and now you want to practice the best in concern placement and keep those controllers of yours really slim. Like me, you may want to try and keep controller feature additions to very specific one liners of code. Organizing your controller code to do just that with ActiveRecord models or even your own custom classes is a pretty easy task, but how do you keep things simple when dealing with controller actions that have to send email AND you want that single email link of code to be responsible for everything in it's own encapsulated way.&lt;/p&gt;


&lt;p&gt;OK, so you want to keep your code placement REALLY organized. You have &lt;a href=&quot;/2008/3/26/don-t-be-a-plinko-programmer&quot;&gt;read about my persnicketyness&lt;/a&gt; and now you want to practice the best in concern placement and keep those controllers of yours really slim. Like me, you may want to try and keep controller feature additions to very specific one liners of code. Organizing your controller code to do just that with ActiveRecord models or even your own custom classes is a pretty easy task, but how do you keep things simple when dealing with controller actions that have to send email AND you want that single email link of code to be responsible for everything in it's own encapsulated way.&lt;/p&gt;

&lt;p&gt;The answer is to push the logic back to the model again. Your controllers should not be concerned with the logic that deals with your own business rules for sending email. The problem with ActionMailer is that most people just use the dynamic &lt;code&gt;MyMailerClass.deliver_&lt;/code&gt; methods that utilize &lt;code&gt;method_missing&lt;/code&gt; to instantiate a mailer classs, and send an email in one fell swoop. I like this usage too, but the challenge is how to tell an instance of a the ActionMailer::Base class that it needs to stop delivery within a method definition that is all set to deliver? The answer is Ruby singleton method magic.&lt;/p&gt; 

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;ActionMailer&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# A simple way to short circuit the delivery of an email from within&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# deliver_* methods defined in ActionMailer::Base subclases.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;do_not_deliver!&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.deliver! ; &lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt; ; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;I suggest placing this code into your &lt;code&gt;lib/core_ext/action_mailer.rb&lt;/code&gt; file. It will allow you to write mailer methods that can short circuit themselves to stop delivery. For instance:

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;MyMailerClass&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActionMailer&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;user_notification&lt;/span&gt;(user)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# ... &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    do_not_deliver! &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; user.email.blank?&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# In your controller code.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;MyMailerClass&lt;/span&gt;.deliver_user_notification(&lt;span class=&quot;iv&quot;&gt;@user&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;Now you do not have to worry about placing delivery concerns in the controller and even worse duplicate that code when you have to use the same mailer method in multiple places. This works by letting the instance of the ActionMailer::Base class define it's own deliver! method which trumps the delier! method called by that object normally defined in ActionMailer::Base.&lt;/p&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ruby-doc.org/docs/UsersGuide/rg/singletonmethods.html&quot; class=&quot;external-link&quot;&gt;About Singleton Methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://redhanded.hobix.com/inspect/methodsThatSelfDestruct.html&quot; class=&quot;external-link&quot;&gt;Methods That Self-Destruct&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-04-03:124</id>
    <published>2008-04-03T22:45:00Z</published>
    <updated>2008-04-03T23:01:59Z</updated>
    <category term="Apple/OSX"/>
    <category term="apple"/>
    <category term="ifreemem"/>
    <category term="macbook"/>
    <category term="memory"/>
    <category term="ram"/>
    <link href="http://www.metaskills.net/2008/4/3/macbook-with-4gb-of-memory" rel="alternate" type="text/html"/>
    <title>MacBook With 4GB Of Memory</title>
<content type="html">
            &lt;p&gt;My MacBook is about a year old now and I've read in &lt;a href=&quot;http://forums.macrumors.com/showthread.php?t=364707&quot; class=&quot;external-link&quot;&gt;quite a few places&lt;/a&gt; that they could be upgraded to around 3.3GB of memory for this specific model. Unlike the latest MacBook which can &quot;as advertised&quot; accommodate 4GB of memory, the theory was that the Santa Rosa chipset can address all 4GB. It could very well be that technically my MacBook is only using ~3.3GB of that memory but the performance has been significant for a very &lt;a href=&quot;http://www.crucial.com/store/partspecs.aspx?imodule=CT25664AC667&quot; class=&quot;external-link&quot;&gt;cheap stick of RAM&lt;/a&gt;. I highly recommend Crucial.&lt;p&gt;

&lt;p&gt;I think this upgrade will have to hold me for some time. In general it has really helped my uptime. Odd as that is I think working with only 2GB of memory caused a lot of IO swap and memory corruption. Especially when stopping and starting so many different mongrels for local Rails development. As of this writing I have not found an issue that I have had to reboot for... uptime 10 days and going strong.&lt;/p&gt;

&lt;p&gt;To keep my uptime going strong, I just purchased an app called &lt;a href=&quot;http://www.activata.co.uk/ifreemem/&quot; class=&quot;external-link&quot;&gt;iFreeMem&lt;/a&gt; today after reading about it on &lt;a href=&quot;http://www.tuaw.com/&quot; class=&quot;external-link&quot;&gt;TUAW&lt;/a&gt;. Because I use PhotoShop ever now and then it really helped having this utility free up some memory that it would not release. So far it is working great!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-03-26:123</id>
    <published>2008-03-26T22:35:00Z</published>
    <updated>2008-03-27T14:40:36Z</updated>
    <category term="Lifestyle"/>
    <category term="Miscellaneous"/>
    <category term="Ruby/Rails"/>
    <category term="codestyle"/>
    <category term="plinko"/>
    <category term="programming"/>
    <category term="ruby"/>
    <link href="http://www.metaskills.net/2008/3/26/don-t-be-a-plinko-programmer" rel="alternate" type="text/html"/>
    <title>Don't Be A Plinko Programmer</title>
<summary type="html">&lt;p&gt;
  One of the things that I have really grown persnickety about is the placement of code. For example, I am a huge advocate that controllers in a rails project should read like a mini Domain Specific Language (DSL) and that as much logic as possible be delegated to the models. In my opinion the best way to do that in a Rails project is to learn the proper usage of ActiveRecord Association Extensions. You can check out the Rails API &lt;a href=&quot;http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html&quot; class=&quot;external-link&quot;&gt;on this page&lt;/a&gt; and scroll down to the section called &quot;Association Extensions&quot; if you read the official docs. In short:
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;
  One of the things that I have really grown persnickety about is the placement of code. For example, I am a huge advocate that controllers in a rails project should read like a mini Domain Specific Language (DSL) and that as much logic as possible be delegated to the models. In my opinion the best way to do that in a Rails project is to learn the proper usage of ActiveRecord Association Extensions. You can check out the Rails API &lt;a href=&quot;http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html&quot; class=&quot;external-link&quot;&gt;on this page&lt;/a&gt; and scroll down to the section called &quot;Association Extensions&quot; if you read the official docs. In short:
&lt;/p&gt;


&lt;p&gt;
  One of the things that I have really grown persnickety about is the placement of code. For example, I am a huge advocate that controllers in a rails project should read like a mini Domain Specific Language (DSL) and that as much logic as possible be delegated to the models. In my opinion the best way to do that in a Rails project is to learn the proper usage of ActiveRecord Association Extensions. You can check out the Rails API &lt;a href=&quot;http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html&quot; class=&quot;external-link&quot;&gt;on this page&lt;/a&gt; and scroll down to the section called &quot;Association Extensions&quot; if you read the official docs. In short:
&lt;/p&gt;&lt;br /&gt;

&lt;blockquote&gt;
  &lt;div&gt;
    The proxy objects that control the access to associations can be extended through anonymous modules. 
    This is especially beneficial for adding new finders, creators, and other factory-type methods that are only used as part of this association.
  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Now this brings me to the topic of my article, what is a Plinko Programmer. If you have no class and don't even know what Plinko is, &lt;a href=&quot;http://en.wikipedia.org/wiki/Plinko&quot; class=&quot;external-link&quot;&gt;Wikipedia has a great write up&lt;/a&gt; on it. A Plinko Programmer is someone that writes code which smells in a few ways. For instance they use excessive arguments in their methods and unnecessarily pass objects around as arguments. They like to bake their own &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Enumerable.html&quot; class=&quot;external-link&quot;&gt;Enumerable&lt;/a&gt; methods vs using the ones readily available. They even like to create large class level methods, or even worse controller actions, that really should be factory methods in 2 or more classes. The analogy is akin to much of the Java code I have rewritten in Rails. Plinko code is long and full of if/else conditions, it's just like the game. You drop an object in the top and just watch it &quot;by chance&quot; work it's way thru the method/function. It is a nasty way to write code and if for anything else it is illegible and hard to test.
&lt;/p&gt;


&lt;h2&gt;What Is The Right Way?&lt;/h2&gt;

&lt;p&gt;
  Here is a short example of how to use Association Extensions. This is a simple example, but when you get used to really using association extensions you will begin to see just how much of your code really belongs there. Let's assume you have a simple invoice and items class.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Invoice&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_many &lt;span class=&quot;sy&quot;&gt;:items&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InvoiceItem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;invoice_id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;InvoiceItem&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  belongs_to &lt;span class=&quot;sy&quot;&gt;:invoice&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;total&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Some complex stuff&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;
  Now let's say that you want to have a clean little method for getting the total of the Invoice object. Resist the temptation to simple add an instance method to the Invoice class. Although it is logical to have &lt;code&gt;@invoice.total&lt;/code&gt; it is better to add it too the association extension. Why? Well think about it, what are you doing? The answer is that you are working with a &quot;collection&quot; of InvoiceItems. It turns out that this is the first part of what the association extension is for, an easy way to work with a collection that has the benefits of knowing how to proxy to methods that can reflect back down to the original caller. It's hard to explain but I'll just leave you with my persnickety code example. Your general rule should be if you are working with the collection in part or in total, then the association extension is the place for it. Keep in mind that so far I have only talked about has_may association extensions, you can do these for one-to-on belongs_to and has_one associations as well.
&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Invoice&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_many &lt;span class=&quot;sy&quot;&gt;:items&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InvoiceItem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;invoice_id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;total&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      proxy_target.map(&amp;amp;&lt;span class=&quot;sy&quot;&gt;:total&lt;/span&gt;).sum&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;InvoiceItem&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  belongs_to &lt;span class=&quot;sy&quot;&gt;:invoice&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;total&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Some complex stuff&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Would yeild code like:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;iv&quot;&gt;@invoice&lt;/span&gt;.items.total&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;P.S. Here lately I've been creating an app/concerns directory where I put modules that encompass mixed in behavior in so many ways for top level models. Typically these modules/concerns shared instance and class methods with two or more primary classes. They have become an excellent home for association extensions since many large applications will define the same association from different models in the object. To keep the code from duplicating in those different models it is better to do something like this&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# This file &amp;quot;invoice_item_concerns.rb&amp;quot; would reside in app/concerns&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;InvoiceItemConcerns&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;AssociationExtensions&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;total&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      proxy_target.map(&amp;amp;&lt;span class=&quot;sy&quot;&gt;:total&lt;/span&gt;).sum&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Invoice&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_many &lt;span class=&quot;sy&quot;&gt;:items&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InvoiceItem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;invoice_id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:extend&lt;/span&gt; =&amp;gt; &lt;span class=&quot;co&quot;&gt;InvoiceItemConcerns&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;AssociationExtensions&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;PackingSlip&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_many &lt;span class=&quot;sy&quot;&gt;:shipments&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InvoiceItem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;packing_slip_id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:extend&lt;/span&gt; =&amp;gt; &lt;span class=&quot;co&quot;&gt;InvoiceItemConcerns&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;AssociationExtensions&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;InvoiceItem&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  belongs_to &lt;span class=&quot;sy&quot;&gt;:invoice&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;total&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Some complex stuff&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Would yeild code like:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;iv&quot;&gt;@invoice&lt;/span&gt;.items.total&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;iv&quot;&gt;@packing_slip&lt;/span&gt;.shipments.total&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          </content>  </entry>
  <entry xml:base="http://www.metaskills.net/">
    <author>
      <name>kencollins</name>
    </author>
    <id>tag:www.metaskills.net,2008-03-22:122</id>
    <published>2008-03-22T01:51:00Z</published>
    <updated>2008-03-22T02:47:29Z</updated>
    <category term="Heuristics"/>
    <category term="mephisto"/>
    <category term="metatheme"/>
    <link href="http://www.metaskills.net/2008/3/22/metaskills-net-reborn-on-mephisto" rel="alternate" type="text/html"/>
    <title>MetaSkills.net Reborn on Mephisto</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;/files/metatheme/meta_drax2.png&quot; alt=&quot;Drax&quot; /&gt;Well after a year of neglect, the MetaSkills.net blog has been &lt;a href=&quot;/meta-theme-for-mephisto&quot;&gt;reborn on Mephisto&lt;/a&gt;. Previously I was using Drupal and it finally got to a point where I was so deep into ruby that I did not even have the gumption to open up a PHP session to publish anything. The sad part is that I told myself that this PHP disdain would help me get off my butt and move to Mephisto. You know, eat my own dog food – obviously procrastination won out – but not forever. For the past week I worked hard to get the Meta theme for Drupal converted to Mephisto. You can use this theme yourself if you want, the source is available on &lt;a href=&quot;http://github.com/metaskills/metatheme/tree/master&quot; class=&quot;external-link&quot;&gt;my github&lt;/a&gt; and I am making updates often. Heck... feel free to fork the project and make some changes or let me know if you want me to incorporate them into mine.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;/files/metatheme/meta_drax2.png&quot; alt=&quot;Drax&quot; /&gt;Well after a year of neglect, the MetaSkills.net blog has been &lt;a href=&quot;/meta-theme-for-mephisto&quot;&gt;reborn on Mephisto&lt;/a&gt;. Previously I was using Drupal and it finally got to a point where I was so deep into ruby that I did not even have the gumption to open up a PHP session to publish anything. The sad part is that I told myself that this PHP disdain would help me get off my butt and move to Mephisto. You know, eat my own dog food – obviously procrastination won out – but not forever. For the past week I worked hard to get the Meta theme for Drupal converted to Mephisto. You can use this theme yourself if you want, the source is available on &lt;a href=&quot;http://github.com/metaskills/metatheme/tree/master&quot; class=&quot;external-link&quot;&gt;my github&lt;/a&gt; and I am making updates often. Heck... feel free to fork the project and make some changes or let me know if you want me to incorporate them into mine.&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;/files/metatheme/meta_drax2.png&quot; alt=&quot;Drax&quot; /&gt;Well after a year of neglect, the MetaSkills.net blog has been &lt;a href=&quot;/meta-theme-for-mephisto&quot;&gt;reborn on Mephisto&lt;/a&gt;. Previously I was using Drupal and it finally got to a point where I was so deep into ruby that I did not even have the gumption to open up a PHP session to publish anything. The sad part is that I told myself that this PHP disdain would help me get off my butt and move to Mephisto. You know, eat my own dog food – obviously procrastination won out – but not forever. For the past week I worked hard to get the Meta theme for Drupal converted to Mephisto. You can use this theme yourself if you want, the source is available on &lt;a href=&quot;http://github.com/metaskills/metatheme/tree/master&quot; class=&quot;external-link&quot;&gt;my github&lt;/a&gt; and I am making updates often. Heck... feel free to fork the project and make some changes or let me know if you want me to incorporate them into mine.&lt;/p&gt; 

&lt;p&gt;Here are a few things that I liked about rewriting the Meta theme for Mephisto. First, unlike Drupal, the administration of your Mephisto blog is not inline, but all tucked away in a private admin section. When you make a theme in Drupal, you are burdened to to the task of coding all the admin CSS for the inline admin features. The Meta theme had over 500 lines of CSS just for the Drupal administration. That is all gone and I love keeping theme code focused on doing nothing but presenting the &quot;user&quot; experience.&lt;/p&gt;

&lt;p&gt;Also, when I first wrote the Meta theme I was just a JavaScript beginner. Nowadays I am pretty good at it and have moved away from the simple script like functions that pass arguments around into a full OO style that spawns from smart classes and a persistent state. The Meta theme is now 100% on Prototype and all the interactive features are tightly knit into the MetaTools, MetaSearch, and MetaContent classes. Take a look at the meta.js source if you want. Lastly, if you are on an old Drupal blog looking to get over to Mephisto, maybe this migration script will help.&lt;/p&gt;


&lt;h2&gt;Migration from Drupal to Mephisto&lt;/h2&gt;

&lt;p&gt;This script is what I used in the rails console to populate data from my old Drupal 4.7 blog to Mephisto. This code is untested on the schema of higher versions of Drupal.&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# My Drupal 4.7 to Mephisto Script&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# ----------------------------------------------------------------&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Things I did before&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;#   * Delete all rows from drupal node table where type != 'blog'&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;#   * Remove the type column from the drupal node table&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Things I did afterward&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;#   * Found all comments in the Mephisto contents table that were &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;#     from me and added user_id 1 to them.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Uncomment these if you are debugging the script and want to &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# start off on a clean mephisto install&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# ----------------------------------------------------------------&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Article.find(:all).each(&amp;amp;:destroy)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# CachedPage.delete_all&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# AssignedSection.delete_all&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Tagging.delete_all&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Tag.delete_all&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;iv&quot;&gt;@mysite&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://www.metaskills.net/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;iv&quot;&gt;@home&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Section&lt;/span&gt;.find_by_name(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Home&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;DrupalArticle&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  establish_connection &lt;span class=&quot;sy&quot;&gt;:drupal&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_table_name  &lt;span class=&quot;sy&quot;&gt;:node&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_primary_key &lt;span class=&quot;sy&quot;&gt;:nid&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_many &lt;span class=&quot;sy&quot;&gt;:comments&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;DrupalComment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_one &lt;span class=&quot;sy&quot;&gt;:version&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;DrupalArticleVerson&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;created_at&lt;/span&gt; ; &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.at(&lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;[&lt;span class=&quot;sy&quot;&gt;:created&lt;/span&gt;]) ; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;DrupalArticleVerson&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  establish_connection &lt;span class=&quot;sy&quot;&gt;:drupal&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_table_name  &lt;span class=&quot;sy&quot;&gt;:node_revisions&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_primary_key &lt;span class=&quot;sy&quot;&gt;:vid&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;DrupalComment&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  establish_connection &lt;span class=&quot;sy&quot;&gt;:drupal&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_table_name  &lt;span class=&quot;sy&quot;&gt;:comments&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_primary_key &lt;span class=&quot;sy&quot;&gt;:cid&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  belongs_to &lt;span class=&quot;sy&quot;&gt;:article&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:class_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;DrupalArticle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:foreign_key&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;DrupalArticle&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;).each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |da|&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;# Creating the article&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  na = &lt;span class=&quot;co&quot;&gt;Article&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;  na.site_id      = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  na.created_at   = da.created_at&lt;tt&gt;
&lt;/tt&gt;  na.published_at = da.created_at&lt;tt&gt;
&lt;/tt&gt;  na.updated_at   = &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;  na.title        = da.title&lt;tt&gt;
&lt;/tt&gt;  na.body         = da.version.body&lt;tt&gt;
&lt;/tt&gt;  na.excerpt      = da.version.teaser&lt;tt&gt;
&lt;/tt&gt;  na.updater_id   = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  na.user_id      = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  na.save!&lt;tt&gt;
&lt;/tt&gt;  na.sections &amp;lt;&amp;lt; &lt;span class=&quot;iv&quot;&gt;@home&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;# Creating comments for this article&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  da.comments.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |dac|&lt;tt&gt;
&lt;/tt&gt;    nac = na.comments.build&lt;tt&gt;
&lt;/tt&gt;    nac.site_id       = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    nac.created_at    = &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.at(dac.timestamp)&lt;tt&gt;
&lt;/tt&gt;    nac.published_at  = &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.at(dac.timestamp)&lt;tt&gt;
