<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SHA Web Team Blog</title>
	<atom:link href="http://opensource.sha.cornell.edu/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://opensource.sha.cornell.edu/blog</link>
	<description>Web Development Jiu-Jitsu at Cornell University</description>
	<lastBuildDate>Tue, 24 Nov 2009 16:45:47 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Ruby Trick Of the Day</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/11/24/ruby-trick-of-the-day/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/11/24/ruby-trick-of-the-day/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 16:44:49 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[snippet]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=178</guid>
		<description><![CDATA[I was browsing through the Rails source code, and came across this nice little snippet.  To paraphrase:

&#91;&#34;val1&#34;,&#34;val2&#34;,&#34;val3&#34;&#93; * '&#38;'
# returns =&#62; &#34;val1&#38;val2&#38;val3&#34;

Yes, multiplying an array by a string does the equivalent of an array join() method.  So the above is equivalent to:

&#91;&#34;val1&#34;,&#34;val2&#34;,&#34;val3&#34;&#93;.join&#40;'&#38;'&#41;
# returns =&#62; &#34;val1&#38;val2&#38;val3&#34;

]]></description>
			<content:encoded><![CDATA[<p>I was browsing through the Rails source code, and came across this nice little snippet.  To paraphrase:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;val1&quot;</span>,<span style="color:#996600;">&quot;val2&quot;</span>,<span style="color:#996600;">&quot;val3&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">*</span> <span style="color:#996600;">'&amp;'</span>
<span style="color:#008000; font-style:italic;"># returns =&gt; &quot;val1&amp;val2&amp;val3&quot;</span></pre></div></div>

<p>Yes, multiplying an array by a string does the equivalent of an array <code>join()</code> method.  So the above is equivalent to:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;val1&quot;</span>,<span style="color:#996600;">&quot;val2&quot;</span>,<span style="color:#996600;">&quot;val3&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'&amp;'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#008000; font-style:italic;"># returns =&gt; &quot;val1&amp;val2&amp;val3&quot;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/11/24/ruby-trick-of-the-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Google To Host Your Javascript Assets</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/11/18/using-google-to-host-your-javascript-assets/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/11/18/using-google-to-host-your-javascript-assets/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 14:47:00 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Errata]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=173</guid>
		<description><![CDATA[Well, not all of them, but some big ones.
I noticed the other day, via Google&#8217;s AJAX Libraries page, that they host a variety of popular JS frameworks that you can load directly via the standard &#60;script/&#62; tag. So instead of hosting, say, JQuery, on my own server, I can just reference Google&#8217;s copy like this:

&#60;script [...]]]></description>
			<content:encoded><![CDATA[<p>Well, not all of them, but some big ones.</p>
<p>I noticed the other day, via Google&#8217;s AJAX Libraries page, that they host a variety of popular JS frameworks that you can load directly via the standard <code>&lt;script/&gt;</code> tag. So instead of hosting, say, JQuery, on my own server, I can just reference Google&#8217;s copy like this:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;script language=&quot;javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre></div></div>

<p>It&#8217;s like having your own basic asset host. <a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#AjaxLibraries">Here&#8217;s the full list</a>, (hint: includes JQuery, Prototype, the Yahoo UI library, and a few others).</p>
<p>So why would you want to do this?  Two reasons:</p>
<ol>
<li>HTTP can only have two concurrent requests from a single server.  That means everything from your site will is downloaded two-at-a-time.  If you&#8217;re loading a lot of different resources (images, css files, js files, etc), they all have to wait in line to be downloaded.  But if you link to your JS library via Google, that&#8217;s a new server, and the browser can call that independently from the other resources on your site.  This means your page will load faster.</li>
<li>You save bandwidth.  Those JS libraries can be reasonably large, but with this method, Google pays for that bandwidth, not you.</li>
</ol>
<p>Google claims that it will host these files &#8220;indefinitely&#8221;, but even if they don&#8217;t, it&#8217;s a reasonably quick action to re-set the reference back to your own server.</p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/11/18/using-google-to-host-your-javascript-assets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Morning Read</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/11/16/the-morning-read-2/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/11/16/the-morning-read-2/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 14:32:19 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=153</guid>
		<description><![CDATA[Metaprogramming in Ruby seems to be today&#8217;s topic:

Understanding Ruby Singleton Classes &#8211; a.k.a. &#8220;anonymous classes&#8221;, these are not to be confused with the singleton pattern, which was news to me.
Metaprogramming in Ruby: It&#8217;s All About the Self &#8211; details the subtle differences in the &#8220;self&#8221; object during runtime and the effects of Ruby&#8217;s &#8220;metaclass&#8221; structure.
The [...]]]></description>
			<content:encoded><![CDATA[<p>Metaprogramming in Ruby seems to be today&#8217;s topic:</p>
<ul>
<li><a href="http://www.contextualdevelopment.com/articles/2008/ruby-singleton">Understanding Ruby Singleton Classes</a> &#8211; a.k.a. &#8220;anonymous classes&#8221;, these are not to be confused with the singleton pattern, which was news to me.</li>
<li><a href="http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/">Metaprogramming in Ruby: It&#8217;s All About the Self</a> &#8211; details the subtle differences in the &#8220;self&#8221; object during runtime and the effects of Ruby&#8217;s &#8220;metaclass&#8221; structure.</li>
<li><a href="http://www.startupcrawl.com/">The First Annual Startup Crawl</a> &#8211; Tour through some new (Rails-focused) web startups in San Francisco.  I can&#8217;t decide if this is really obnoxious or not.  Probably because I&#8217;m not in San Francisco working in a Rails startup.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/11/16/the-morning-read-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CU Web Forum Talk Up on SlideShare</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/11/15/cu-web-forum-talk-up-on-slideshare/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/11/15/cu-web-forum-talk-up-on-slideshare/#comments</comments>
		<pubDate>Sun, 15 Nov 2009 19:15:55 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Errata]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[presentations]]></category>
		<category><![CDATA[rails love]]></category>
		<category><![CDATA[self-promotion]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=149</guid>
		<description><![CDATA[For any interested parties, I posted my recent talk where I presented about Ruby on Rails to the Cornell Web Development community.  The talk is two parts, the first being a background to Ruby on Rails, and the second covering the challenges and payoffs that came from integrating Rails into our PHP/Oracle environment.
You can [...]]]></description>
			<content:encoded><![CDATA[<p>For any interested parties, I posted my recent talk where I presented about Ruby on Rails to the <a href="https://confluence.cornell.edu/display/CUWEBFORUM/Cornell+Web+Knowledgebase">Cornell Web Development community</a>.  The talk is two parts, the first being a background to Ruby on Rails, and the second covering the challenges and payoffs that came from integrating Rails into our PHP/Oracle environment.</p>
<p>You can see the full thing at:<br />
<a href="http://www.slideshare.net/daphonz/moving-to-ruby-on-rails-a-love-story">http://www.slideshare.net/daphonz/moving-to-ruby-on-rails-a-love-story</a></p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/11/15/cu-web-forum-talk-up-on-slideshare/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Oracle ENV Vars in Phusion Passenger</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/11/11/oracle-env-vars-in-phusion-passenger/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/11/11/oracle-env-vars-in-phusion-passenger/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 20:46:28 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=144</guid>
		<description><![CDATA[Rails&#8217; oracle adapter needs to see your Oracle environment variables in order to hook up to the database.  In an old post, I described how to do that before Phusion Passenger could handle it naturally.  As of 2.2.3, Passenger can now pass server ENV variables to the Rails environment directly, via the &#8220;PassEnv&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>Rails&#8217; oracle adapter needs to see your Oracle environment variables in order to hook up to the database.  In an <a href="http://opensource.sha.cornell.edu/blog/2009/03/23/rails-with-phusion-passenger-and-oracle/">old post</a>, I described how to do that before Phusion Passenger could handle it naturally.  As of 2.2.3, Passenger can now pass server ENV variables to the Rails environment directly, via the &#8220;PassEnv&#8221; command.</p>
<p>So now, in your httpd.conf, you can add the following:</p>

<div class="wp_syntax"><div class="code"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">PassEnv</span> LD_LIBRARY_PATH
<span style="color: #00007f;">PassEnv</span> ORACLE_HOME
<span style="color: #00007f;">PassEnv</span> NLS_LANG
<span style="color: #00007f;">PassEnv</span> TNS_ADMIN</pre></div></div>

<p>That&#8217;s it!  You no longer need to create a wrapper for the ruby interpreter.</p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/11/11/oracle-env-vars-in-phusion-passenger/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Morning Read</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/09/30/the-morning-read/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/09/30/the-morning-read/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 14:48:08 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Meta]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=140</guid>
		<description><![CDATA[Samples of today&#8217;s self-education:

UI Fundamentals for Programmers From Ryan Singer at 37 Signals.  Excellent discussion on function-driven design, and a nice smackdown of Balsamiq at the end.
RailsCast: Include vs. Joins Helped to firm up my understand of :include and :joins in ActiveRecord.
Why Stylesheet Abstraction Matters A programmatic approach to CSS.  It may be [...]]]></description>
			<content:encoded><![CDATA[<p>Samples of today&#8217;s self-education:</p>
<ul>
<li><a href="http://37signals.com/svn/posts/1952-i-gave-a-talk-on-ui-fundamentals-for-programmers">UI Fundamentals for Programmers</a> From Ryan Singer at 37 Signals.  Excellent discussion on function-driven design, and a nice smackdown of Balsamiq at the end.</li>
<li><a href="http://railscasts.com/episodes/181-include-vs-joins">RailsCast: Include vs. Joins</a> Helped to firm up my understand of <code>:include</code> and <code>:joins</code> in ActiveRecord.</li>
<li><a href="http://chriseppstein.github.com/blog/2009/09/20/why-stylesheet-abstraction-matters/">Why Stylesheet Abstraction Matters</a> A programmatic approach to CSS.  It may be time to start learning this. (via <a href="http://afreshcup.com/2009/09/30/double-shot-551/">A Fresh Cup</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/09/30/the-morning-read/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sharing A Workspace With Perforce</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/09/29/sharing-a-workspace-with-perforce/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/09/29/sharing-a-workspace-with-perforce/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 15:30:11 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Errata]]></category>
		<category><![CDATA[perforce]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=136</guid>
		<description><![CDATA[We here at the SHA webteam use Perforce for our version control system.  It&#8217;s nice in many ways, but it can be a little unwieldy at times.  Recently, I wanted to use a second computer at work, but wanted to use the same workspace I&#8217;ve been using for the past year.  My [...]]]></description>
			<content:encoded><![CDATA[<p>We here at the SHA webteam use Perforce for our version control system.  It&#8217;s nice in many ways, but it can be a little unwieldy at times.  Recently, I wanted to use a second computer at work, but wanted to use the same workspace I&#8217;ve been using for the past year.  My workspace is stored on a networked drive, which is linked to a development server and so forth.</p>
<p>By default a Perforce workspace is tied to one &#8220;host&#8221; and one &#8220;root&#8221;.  The host is the hostname of your computer on the network, and the root is the location in the file system where the workspace resides.  If you try to access the workspace via another computer, Perforce will prevent you from doing so, declaring that the workspace is inaccessible from any computer that&#8217;s not the default host.</p>
<p>Luckily, we can change this.  In your client spec in perforce, we need to do two things:</p>
<ul>
<li>Remove the host name from the host section</li>
<li>Add an additional file system path to the &#8220;AltRoots&#8221; section</li>
</ul>
<p>Removing the original hostname for your workspace effectively removes that requirement from Perforce, and adding the additional file system path tells it how to access the workspace from  your other computer.</p>
<p>So say I have a default setup on a PC, and the clientspec contains:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">host: SHA-casey
root: J:\perforce\depots\cjd47</pre></div></div>

<p>In order to make this work with a Mac, I need to know the location of the depot in the Mac&#8217;s filesystem.  If we&#8217;re mounting a SAMBA drive or something, it should be located in the /Volumes directory like so:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">/</span>Volumes<span style="color: #000000; font-weight: bold;">/</span>FILESTORE<span style="color: #000000; font-weight: bold;">/</span>perforce<span style="color: #000000; font-weight: bold;">/</span>depots<span style="color: #000000; font-weight: bold;">/</span>cjd47</pre></div></div>

<p>So my modifed clientspec would look something like:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">host: 
root: J:\perforce\depots\cjd47
AltRoots: <span style="color: #000000; font-weight: bold;">/</span>Volumes<span style="color: #000000; font-weight: bold;">/</span>FILESTORE<span style="color: #000000; font-weight: bold;">/</span>perforce<span style="color: #000000; font-weight: bold;">/</span>depots<span style="color: #000000; font-weight: bold;">/</span>cjd47</pre></div></div>

<p>Everything else in the client spec on the new computer should be the same as the original client name, workspace name, views, etc.  When you connect with Perforce, everything should work just fine.</p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/09/29/sharing-a-workspace-with-perforce/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why You Don&#8217;t Need an AfterFind Callback in Rails</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/06/04/why-you-dont-need-an-afterfind-callback-in-rails/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/06/04/why-you-dont-need-an-afterfind-callback-in-rails/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 14:08:54 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[callbacks]]></category>
		<category><![CDATA[dry]]></category>
		<category><![CDATA[rails love]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=120</guid>
		<description><![CDATA[I came to Rails from a background in CakePHP.  In the course of my experience with that framework, I really started to embrace the concept of Model callbacks: methods that are run automatically at specifics points during common actions, like beforeSave, beforeRender, afterSave, and afterFind, to name a few.
I used to use the afterFind [...]]]></description>
			<content:encoded><![CDATA[<p>I came to Rails from a background in <a href="http://www.cakephp.org">CakePHP</a>.  In the course of my experience with that framework, I really started to embrace the concept of Model callbacks: methods that are run automatically at specifics points during common actions, like <a href="http://book.cakephp.org/view/76/Callback-Methods">beforeSave, beforeRender, afterSave, and afterFind</a>, to name a few.</p>
<p>I used to use the afterFind callback quite a bit in Cake, mainly to standardize the data coming out of the model, or to run occasional queries that I didn&#8217;t want to associate directly through the find() method.</p>
<p>So when I moved over to Rails, I started to poke around a bit looking for callback methods.  And while I <a href="http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html">found them</a>, there seemed to be a lack of focus on the after_find callback, as well as a general lack of details or examples online.  Plus, it looked like there&#8217;s a huge performance hit when you use it.</p>
<p>So why the lack of focus?  Surely most people want ways to play with returned data from a find() method call?</p>
<p>And then I realized what is probably obvious to most people: Rails returns model objects, not arrays.</p>
<p>Objects have that nice feature of being able to define arbitrary methods that you can execute at will.  This ability limits the need for an after_find method to go through and add or change some data in most cases.  This is why it seems to be rarely used.</p>
<p>To really see the difference, let&#8217;s look at a slightly contrived example.</p>
<p>Say I have a Product model that includes a field for weight (in pounds). When I display this data in my view, I want to display the English units and the metric units for its weight, but I don&#8217;t want to write out the conversion code in the view every time.</p>
<p>Using the afterFind() callback in CakePHP, I&#8217;d have to do something like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> Product <span style="color: #000000; font-weight: bold;">extends</span> AppModel <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> add_weight_types<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight_in_lbs'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span> <span style="color: #0000ff;">' lbs'</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight_in_kg'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">/</span> <span style="color:#800080;">2.2</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">' kg'</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #b1b100;">return</span> <span style="color: #000088;">$data</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">function</span> afterFind<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_weight_types</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">elseif</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><span style="color: #000088;">$i</span><span style="color: #339933;">&lt;</span>count<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          <span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_weight_types</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$data</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Notice I had to take into account the two differing data structures that CakePHP returns: the find(&#8217;all&#8217;) method that returns an array of model arrays, or the find(&#8217;first&#8217;) method that returns a single model array.  Every find call now adds two additional array items for the weight that I can use in my views:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Product Weight: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'Product'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight_in_lbs'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span> <span style="color: #0000ff;">' ('</span><span style="color: #339933;">.</span> <span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'Product'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'weight_in_kg'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">')'</span><span style="color: #339933;">;</span></pre></div></div>

<p>Rails, because it returns arrays of model <strong>objects</strong>, allows us to have a much simpler implementation.  Start in the Product Model again:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Product <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> weight_in_kg
    <span style="color:#996600;">&quot;$.2f kg&quot;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#006600; font-weight:bold;">&#40;</span>weight.<span style="color:#9900CC;">to_f</span> <span style="color:#006600; font-weight:bold;">/</span> <span style="color:#006666;">2.2</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> weight_in_lbs
    <span style="color:#996600;">&quot;$.2f lbs&quot;</span> <span style="color:#006600; font-weight:bold;">%</span> weight
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span></pre></td></tr></table></div>

<p>Notice there&#8217;s no callback needed for this.  The code only executes when it&#8217;s called in a view, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">Product Weight: <span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#0066ff; font-weight:bold;">@product</span>.<span style="color:#9900CC;">weight_in_lbs</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> (<span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#0066ff; font-weight:bold;">@product</span>.<span style="color:#9900CC;">weight_in_kg</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>)</pre></div></div>

<p>Man, that&#8217;s nice.  It just feels <em>good</em>, you know?</p>
<p>CakePHP is great in many, many ways, but for someone who learned a lot about programming by using that framework, I&#8217;m realizing now how many unconscious thought patterns it instilled in me. Rails is a good extension of that framework concept at a higher level of complexity, and after working with Rails for a while, I began to break out of the Cake thought-pattern (and most likely moved well in the Rails thought-pattern instead).</p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/06/04/why-you-dont-need-an-afterfind-callback-in-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>So I Gave This Talk&#8230;.</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/05/08/so-i-gave-this-talk/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/05/08/so-i-gave-this-talk/#comments</comments>
		<pubDate>Fri, 08 May 2009 14:14:11 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Meta]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[highedwebdev]]></category>
		<category><![CDATA[presentations]]></category>
		<category><![CDATA[self-promotion]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=110</guid>
		<description><![CDATA[I was fortunate enough to have the opportunity to give a talk about our recent work with the SHA LaunchPad redesign and Rails project for the regional conference of the Higher Education Web Professionals Organization, which was hosted here at Cornell by the tireless Jason Woodward.
It was a great conference, with some very interesting talks. [...]]]></description>
			<content:encoded><![CDATA[<p>I was fortunate enough to have the opportunity to give a talk about our recent work with the SHA LaunchPad redesign and Rails project for the <a href="http://highedweb.cals.cornell.edu/2009/Home">regional conference of the Higher Education Web Professionals Organization</a>, which was hosted here at Cornell by the tireless <a href="http://www.linkedin.com/pub/3/847/a53">Jason Woodward</a>.</p>
<p>It was a great conference, with some <a href="http://www.slideshare.net/jrrodgers/web-project-management-1337198">very</a> <a href="http://highedweb.cals.cornell.edu/2009/Schedule">interesting</a> <a href="http://www.markgr.com/hewebcornell/">talks</a>.  The slides for mine, which mostly deal with the concept and philosophy behind our LaunchPad site (which is still not live, sorry), are on SlideShare, so you can see (not hear, unfortunately) <a href="http://www.slideshare.net/daphonz/building-a-new-launchpad-from-the-ground-up?type=powerpoint">Building a New LaunchPad From the Ground Up.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/05/08/so-i-gave-this-talk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Did you know that POST variables are always passed as strings?</title>
		<link>http://opensource.sha.cornell.edu/blog/2009/05/08/did-you-know-that-post-variables-are-always-passed-as-strings/</link>
		<comments>http://opensource.sha.cornell.edu/blog/2009/05/08/did-you-know-that-post-variables-are-always-passed-as-strings/#comments</comments>
		<pubDate>Fri, 08 May 2009 13:57:38 +0000</pubDate>
		<dc:creator>Casey Dreier</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[frustration]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://opensource.sha.cornell.edu/blog/?p=104</guid>
		<description><![CDATA[Because I didn&#8217;t.  Or at least I didn&#8217;t think much about it.  And dammit, I should&#8217;ve.
As you can probably tell, I spent a long time trying to figure out a very simple problem.  This is one of those posts that is inspired by the (vain) hope that maybe, just maybe, I can spare someone [...]]]></description>
			<content:encoded><![CDATA[<p>Because I didn&#8217;t.  Or at least I didn&#8217;t think much about it.  And dammit, I should&#8217;ve.</p>
<p>As you can probably tell, I spent a long time trying to figure out a very simple problem.  This is one of those posts that is inspired by the (vain) hope that maybe, just maybe, I can spare someone else a few hours of confusion so they can do better things, like go outside and eat ice cream or something.</p>
<p>Here&#8217;s the (simplified) situation.  The user can select a variety of widgets via checkboxes in a form.  The information gets passed as widget ids to the controller, which triggers a method that updates the assocation of a user&#8217;s widgets:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;">### WidgetsController ###</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> updatewidgets
  <span style="color:#0066ff; font-weight:bold;">@user</span>.<span style="color:#9900CC;">update_active_widgets</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:widget_ids</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> request.<span style="color:#9900CC;">post</span>?
  redirect <span style="color:#996600;">&quot;/&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;">### User Model ###</span>
has_many <span style="color:#ff3333; font-weight:bold;">:widgets</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> update_active_widgets<span style="color:#006600; font-weight:bold;">&#40;</span>new_widget_ids<span style="color:#006600; font-weight:bold;">&#41;</span>
  current_widget_ids = <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">widget_ids</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># return an array of widget ids that the user no longer wants #</span>
  unbound_widget_ids = current_widget_ids <span style="color:#006600; font-weight:bold;">-</span> new_widget_ids
&nbsp;
  <span style="color:#008000; font-style:italic;"># Delete all unbound widgets... save new widgets....etc...etc...#</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Ok, who can see why this deletes all of the user&#8217;s widgets every time we run this script?  Hint: I already told you in the title of this post.</p>
<p>Since the <code>params[:widget_ids]</code> is coming from a POST request, every item in the array is going to be a string, even if it was listed as a number.  So, if the user selected widget_ids of 1, 2, and 3, the incoming <code>params[:widget_ids]</code> array would look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:widget_ids</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;1&quot;</span>,<span style="color:#996600;">&quot;2&quot;</span>,<span style="color:#996600;">&quot;3&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span></pre></div></div>

<p>In my method, <code>update_active_widgets</code>, I take a set difference between two arrays to find which of the current widget_ids associated with the user are no longer selected by the user.  But the when I pull out the current widget ids using <code>self.widget_ids</code>, I get an array of <em>integers</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">widget_ids</span> = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>,<span style="color:#006666;">2</span>,<span style="color:#006666;">4</span>,<span style="color:#006666;">6</span><span style="color:#006600; font-weight:bold;">&#93;</span></pre></div></div>

<p>So when I take the set difference between an array of strings and an array of integers, Ruby understands them to be totally different, &#8220;1&#8243; != 1.  So what I was doing was this:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">unbound_widget_ids = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>,<span style="color:#006666;">2</span>,<span style="color:#006666;">4</span>,<span style="color:#006666;">6</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;1&quot;</span>,<span style="color:#996600;">&quot;2&quot;</span>,<span style="color:#996600;">&quot;3&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#008000; font-style:italic;"># returns the original set [1,2,4,6]</span></pre></div></div>

<p>Thus, I&#8217;ve just told Rails that every current widget_id is unbound, and should be deleted.  Since Rails is smart enough to automatically convert a number-string to a number in ActiveRecord, there was never a problem adding widgets.  My unit tests were even passing fine, because I kept entering my widget_ids as integer arrays.</p>
<p>Obviously, the solution is to convert everything to an integer before doing a set difference, something like:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">new_widget_ids = new_widget_ids.<span style="color:#9900CC;">collect</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>w_id<span style="color:#006600; font-weight:bold;">|</span> w_id.<span style="color:#9900CC;">to_i</span><span style="color:#006600; font-weight:bold;">&#125;</span></pre></div></div>

<p>Now, when I do the set difference, what happens is this:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">unbound_widget_ids = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>,<span style="color:#006666;">2</span>,<span style="color:#006666;">4</span>,<span style="color:#006666;">6</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>,<span style="color:#006666;">2</span>,<span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#008000; font-style:italic;"># returns the difference set [4,6]</span></pre></div></div>

<p>And that fixes it.  Widgets with ids 4 and 6 get removed from this user, and we go ahead and add the widget with id 3. Finally.</p>
<p>Regardless, POST values get passed as strings.  I should really know things like this by now.</p>
]]></content:encoded>
			<wfw:commentRss>http://opensource.sha.cornell.edu/blog/2009/05/08/did-you-know-that-post-variables-are-always-passed-as-strings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
