<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title>Mister Bleigh</title>
 
 <link href="http://www.mbleigh.com/" />
 <updated>2009-09-25T14:23:57-07:00</updated>
 <id>http://www.mbleigh.com/</id>
 <author>
   <name>Michael Bleigh</name>
   <email>mbleigh@mbleigh.com</email>
 </author>
 
 
 <link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/2.0/" /><link rel="self" href="http://feeds.feedburner.com/mbleigh" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
   <title>TweetStream: Ruby Access to the Twitter Streaming API</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/yF8r2T8sHfw/tweetstream-ruby-access-to-the-twitter-streaming-api.html" />
   <updated>2009-09-22T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/09/22/tweetstream-ruby-access-to-the-twitter-streaming-api</id>
   <content type="html">&lt;p&gt;Twitter&amp;#8217;s &lt;a href="http://apiwiki.twitter.com/Streaming-API-Documentation"&gt;Streaming &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; is one of the most exciting developments in the Twitter &lt;span class="caps"&gt;API&lt;/span&gt; in some time. It gives you the ability to create a long-standing connection to Twitter that receives &amp;#8220;push&amp;#8221; updates when new tweets matching certain criteria arrive, obviating the need to constantly poll for updates. &lt;a href="http://github.com/intridea/tweetstream"&gt;TweetStream&lt;/a&gt; is a Ruby library to access the new &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Installation of TweetStream is simple, it&amp;#8217;s available as a gem on GitHub and &lt;a href="http://gemcutter.org/"&gt;Gemcutter.org&lt;/a&gt;. To install it from GitHub:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;gem sources -a http://gems.github.com
gem install intridea-tweetstream
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To install it from Gemcutter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;gem sources -a http://gemcutter.org
gem install tweetstream
&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Usage&lt;/h3&gt;
&lt;p&gt;TweetStream creates a long-standing &lt;span class="caps"&gt;HTTP&lt;/span&gt; connection to Twitter, so unlike other Twitter libraries you don&amp;#8217;t simply run it once and deal with the results. Instead, you provide a block that will be yielded to with each new status that arrives. The most basic example is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tweetstream&amp;#39;&lt;/span&gt;

&lt;span class="no"&gt;TweetStream&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pass&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;screen_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This will provide you with a small sample snapshot of all of the updates being posted to Twitter at this moment and print them to the screen. There are also methods available to track single-word keywords as well as the updates of a specified list of user ids (integers, not screen names). You can do that like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Track the terms &amp;#39;keyword1&amp;#39; and &amp;#39;keyword2&amp;#39;&lt;/span&gt;
&lt;span class="no"&gt;TweetStream&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pass&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;keyword1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;keyword2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;screen_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Track users with IDs 123 and 456&lt;/span&gt;
&lt;span class="no"&gt;TweetStream&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pass&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;456&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;screen_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Daemonization&lt;/h3&gt;
&lt;p&gt;One of the most useful features of TweetStream is its built-in daemonization functionality. This allows you to create scripts that run in the background of your machine rather than taking up an active process. To create a daemon script, you simply use &lt;code&gt;TweetStream::Daemon&lt;/code&gt; instead of &lt;code&gt;TweetStream::Client&lt;/code&gt;. Here&amp;#8217;s an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tweetstream&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# The third argument is an optional process name.&lt;/span&gt;
&lt;span class="no"&gt;TweetStream&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Daemon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pass&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tracker&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;keyword1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;keyword2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# Do something like dump the status to ActiveRecord&lt;/span&gt;
  &lt;span class="c1"&gt;# or anything else you want.&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you were to place the above code in a file called &lt;code&gt;tracker.rb&lt;/code&gt; you could then run &lt;code&gt;ruby tracker.rb&lt;/code&gt; to see a list of daemonization commands such as start, stop, or run.&lt;/p&gt;
&lt;p&gt;TweetStream is a simple wrapper on the Streaming &lt;span class="caps"&gt;API&lt;/span&gt;, but with built-in daemonization provides powerfully flexible means of accessing the Twitter Streaming &lt;span class="caps"&gt;API&lt;/span&gt; using familiar Ruby tools. More complete code documentation is &lt;a href="http://rdoc.info/projects/intridea/tweetstream"&gt;available at rdoc.info&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=yF8r2T8sHfw:2_f6lThDkuk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=yF8r2T8sHfw:2_f6lThDkuk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=yF8r2T8sHfw:2_f6lThDkuk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=yF8r2T8sHfw:2_f6lThDkuk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/yF8r2T8sHfw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/09/22/tweetstream-ruby-access-to-the-twitter-streaming-api.html</feedburner:origLink></entry>
 
 <entry>
   <title>CouchDB-Lucene, CouchDBX, and CouchRest</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/BRG2G5faF1c/couchdb-lucene-couchdbx-and-couchrest.html" />
   <updated>2009-09-21T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/09/21/couchdb-lucene-couchdbx-and-couchrest</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been playing a lot with &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; lately and if you&amp;#8217;re on OS X there&amp;#8217;s really no easier way to do so than by using &lt;a href="http://janl.github.com/couchdbx/"&gt;CouchDBX&lt;/a&gt;, a self-contained application that includes CouchDB, Erlang, and all of the dependencies you need to run Couch.&lt;/p&gt;
&lt;p&gt;However, recently I wanted to try the power and functionality of &lt;a href="http://github.com/rnewson/couchdb-lucene"&gt;couchdb-lucene&lt;/a&gt; for full-text indexing of a CouchDB application on which I was working. It wasn&amp;#8217;t immediately obvious to me how to make that happen, so I thought I&amp;#8217;d share how I got it working for those who might want to do the same. For the record, I am using the following versions of things:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Mac OS X 10.6 (Snow Leopard)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://cloud.github.com/downloads/janl/couchdbx-core/CouchDBX-0.9.1-R13B-pl2.zip"&gt;CouchDBX 0.9.1 R13B pl2&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://cloud.github.com/downloads/rnewson/couchdb-lucene/couchdb-lucene-0.4-jar-with-dependencies.jar.gz"&gt;CouchDB Lucene v0.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unpacking CouchDB Lucene&lt;/h3&gt;
&lt;p&gt;You will need to place CouchDB Lucene in a convenient location, but first you&amp;#8217;ll need to unpack the gZip file. Note that, at least for me, &lt;strong&gt;the default Mac unarchiver did not provide a suitable .jar file&lt;/strong&gt;. Instead, follow the &lt;a href="http://cloud.github.com/downloads/rnewson/couchdb-lucene/README"&gt;&lt;span class="caps"&gt;README&lt;/span&gt; instructions&lt;/a&gt; and extract it using the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;unpack200 couchdb-lucene-0.4-jar-with-dependencies.jar.gz couchdb-lucene-0.4-jar-with-dependencies.jar
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It doesn&amp;#8217;t particularly matter where you put it (I put mine in &lt;code&gt;/usr/local/etc&lt;/code&gt;) so long as you remember the location.&lt;/p&gt;
&lt;h3&gt;Editing the CouchDBX .ini File&lt;/h3&gt;
&lt;p&gt;Next you will need to edit the CouchDBX &lt;code&gt;local.ini&lt;/code&gt; file to add the external for full-text indexing. To access the file, right-click CouchDBX and select &amp;#8220;Show Package Contents&amp;#8221; then navigate to &lt;code&gt;Contents/Resources/couchdbx-core/couchdb/etc/couchdb/local.ini&lt;/code&gt; and open it up in your favorite text editor. You will need to add the following lines to this file, taking note to change the directory to match where you stored your Lucene .jar file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;[couchdb]&lt;/span&gt;
&lt;span class="na"&gt;os_process_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;60000 ; increase the timeout from 5 seconds.&lt;/span&gt;

&lt;span class="k"&gt;[external]&lt;/span&gt;
&lt;span class="na"&gt;fti&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/java -server -Xmx1g -jar /path/to/couchdb-lucene-0.4-jar-with-dependencies.jar -search&lt;/span&gt;

&lt;span class="k"&gt;[update_notification]&lt;/span&gt;
&lt;span class="na"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/java -server -Xmx1g -jar  /path/to/couchdb-lucene-0.4-jar-with-dependencies.jar -index&lt;/span&gt;

&lt;span class="k"&gt;[httpd_db_handlers]&lt;/span&gt;
&lt;span class="na"&gt;_fti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;{couch_httpd_external, handle_external_req, &amp;lt;&amp;lt;&amp;quot;fti&amp;quot;&amp;gt;&amp;gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;All right, that&amp;#8217;s all the setup you need to be running CouchDB Lucene! Now you can start up CouchDBX and set up your first search indexes.&lt;/p&gt;
&lt;h3&gt;Creating a Full-Text Index View&lt;/h3&gt;
&lt;p&gt;To create a full-text index view, you simply need to add a &amp;#8220;fulltext&amp;#8221; field to one of your design documents. The &lt;span class="caps"&gt;URL&lt;/span&gt; structure for accessing CouchDB Lucene searches is as follows:&lt;/p&gt;
&lt;pre&gt;http://localhost:5984/database_name/_fti/design_doc_name/index_name?q=your+query+here&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;database_name&lt;/code&gt; is any database you have on your system, &lt;code&gt;design_doc_name&lt;/code&gt; is any design document in your database, and &lt;code&gt;index_name&lt;/code&gt; is a fulltext index you defined. For instance, if I had a &lt;a href="http://github.com/couchrest/couchrest"&gt;CouchRest&lt;/a&gt; generated design doc for a bunch of music, I might have a design document that looks something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_design/Song&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;_rev&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;af12a4b12af1b24afbf244f1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;fulltext&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;my_search&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;function(doc) { if (!doc[&amp;#39;couchrest-type&amp;#39;] == &amp;#39;Song&amp;#39;) return null; var ret = new Document(); ret.add(doc.title); ret.add(doc.artist); return ret; }&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I would then be able to access the search results with this &lt;span class="caps"&gt;URL&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;http://localhost:5984/myapp/_fti/Song/my_search?q=Ben+Folds&lt;/pre&gt;
&lt;p&gt;Awesome! We now have full-text indexing up and running on CouchDBX!&lt;/p&gt;
&lt;h3&gt;Bonus: CouchRest Lucene&lt;/h3&gt;
&lt;p&gt;I use CouchRest extensively in my Ruby CouchDB projects, and I wanted to be able to integrate the new Lucene searches easily. I found &lt;a href="http://zdzolton.wordpress.com/2009/05/04/quick-tip-couchdb-with-lucene-search/"&gt;this post&lt;/a&gt; that added a bit of functionality, but I wanted to be able to integrate with ExtendedDocument (and the snippet was also slightly outdated), so I&amp;#8217;ve updated it. Just add this sometime after you include CouchRest:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CouchRest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Database&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="no"&gt;CouchRest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="no"&gt;CouchRest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paramify_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/_fti/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:q&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CouchRest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ExtendedDocument&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:include_docs&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rows&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;collect!&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;doc&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What this snippet does is allows you to perform searches on a database directly or by calling a search method on an extended document. Let&amp;#8217;s look at a couple examples to see how it would work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vi"&gt;@db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CouchRest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://localhost:5984/myapp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="vi"&gt;@db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Song&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my_search&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ben Folds&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:include_docs&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The following is equivalent to the above, but will automatically&lt;/span&gt;
&lt;span class="c1"&gt;# include the docs and cast the result rows into ExtendedDocuments&lt;/span&gt;
&lt;span class="no"&gt;Song&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my_search&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ben Folds&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now that we have this set up, we&amp;#8217;re ready to go forth and build full-text search into our CouchDB apps. I hope this is helpful to some who have become somewhat familiar with CouchDB but are looking to push it a little further and try out some of the more advanced usages of CouchDB in their applications.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=BRG2G5faF1c:6Rr7zc7t3Fk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=BRG2G5faF1c:6Rr7zc7t3Fk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=BRG2G5faF1c:6Rr7zc7t3Fk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=BRG2G5faF1c:6Rr7zc7t3Fk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/BRG2G5faF1c" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/09/21/couchdb-lucene-couchdbx-and-couchrest.html</feedburner:origLink></entry>
 
 <entry>
   <title>A Fresh Coat of Paint</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/1JpOQ5Go9iM/a-fresh-coat-of-paint.html" />
   <updated>2009-09-20T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/09/20/a-fresh-coat-of-paint</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s been about six months since I moved this blog over to GitHub Pages and Jekyll, and that means that it&amp;#8217;s about time for another site redesign. This time I decided to have a little bit of fun with some CSS3 features such as box shadow but I kept it simple.&lt;/p&gt;
&lt;p&gt;Of course, as with the last page design (that I&amp;#8217;ve been very happy to see many people adopt) you&amp;#8217;re welcome to use this design in part or in whole for your own GitHub pages (the source is &lt;a href="http://github.com/mbleigh/mbleigh.github.com"&gt;still available here&lt;/a&gt;), but it might be a little more difficult due to the iconography and actual use of graphics.&lt;/p&gt;
&lt;p&gt;Thanks, and I hope you keep reading!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=1JpOQ5Go9iM:_yWd1XElGuk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=1JpOQ5Go9iM:_yWd1XElGuk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=1JpOQ5Go9iM:_yWd1XElGuk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=1JpOQ5Go9iM:_yWd1XElGuk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/1JpOQ5Go9iM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/09/20/a-fresh-coat-of-paint.html</feedburner:origLink></entry>
 
 <entry>
   <title>Good Idea, Bad Idea: Rails Rumble Post-Mortem</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/rh4LB07GuUQ/rumble-post-mortem.html" />
   <updated>2009-08-24T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/08/24/rumble-post-mortem</id>
   <content type="html">&lt;div style='float:right; margin: 0 0 10px 10px;'&gt;&lt;img src='http://img.skitch.com/20090824-eefjcq11tdka135rgmqkn8wcbu.jpg' alt='Thingivore.com'/&gt;&lt;/div&gt;
&lt;p&gt;The time has come and gone: the 2009 Rails Rumble is over (from a code perspective, anyway). This year myself and the other members of my team (Brent Collier, Dave Naffis, and Ping Yu) put together &lt;a href="http://www.thingivore.com/"&gt;Thingivore&lt;/a&gt;, a place to show off your collection of movies, games, and books online. As one might expect from a 48-hour marathon application development experience, it was a mixed bag of elation, frustration, fist-pumping and head-hanging as the hours drew to a close. I wanted to take some time to document some of my &amp;#8220;lessons learned&amp;#8221; so to speak for future Rumblers and app developers in general.&lt;/p&gt;
&lt;h3&gt;Good Idea: Have a Server Configuration Guru&lt;/h3&gt;
&lt;p&gt;While the Rumble is primarily a coding contest, it&amp;#8217;s important to note that &lt;strong&gt;someone&lt;/strong&gt; on your team needs to be able to get that Linode server up and running. By having someone who can configure centos servers in their sleep on your team, you don&amp;#8217;t have to sweat bullets at the prospect of &amp;#8220;just getting it running.&amp;#8221; In fact, Dave Naffis (Intridea co-founder and Rails deployment genius) came in and 45 minutes later said &amp;#8220;OK, just hit &lt;code&gt;cap deploy deploy:migrate&lt;/code&gt;&amp;#8221; whenever you want to update the server. This is including setting up &lt;span class="caps"&gt;DNS&lt;/span&gt; for &lt;code&gt;thingivore.com&lt;/code&gt;, getting Ruby, Rails, Apache, Passenger, MySQL, and CouchDB all running and probably all other manner of dark magic I can&amp;#8217;t comprehend.&lt;/p&gt;
&lt;p&gt;Maybe it&amp;#8217;s because I&amp;#8217;m not a server configuration guy, but that&amp;#8217;s exactly the point: I didn&amp;#8217;t have to worry about it and could focus on the design and development instead of worrying about whether or not we were going to get it running on the competition machines.&lt;/p&gt;
&lt;h3&gt;Bad Idea: &amp;#8220;Let&amp;#8217;s Try Something New!&amp;#8221;&lt;/h3&gt;
&lt;p&gt;For some crazy reason, I decided that I wanted to use the Rumble as a way to experiment with new technologies (primarily CouchDB). &lt;strong&gt;Do not do this.&lt;/strong&gt; The Rumble is a time to take the skills you know like the back of your hand and apply them with laser-beam focus to build something awesome and complete in 48 hours. While I&amp;#8217;m happy with our product, there are reams of features that were cut while I scrambled to understand some of the complexities of complex sorts and other issues with CouchRest and CouchDB.&lt;/p&gt;
&lt;p&gt;Of course, it was also fun to learn a new technology and use it in a &amp;#8220;trial by fire&amp;#8221; circumstance, but ultimately if you want to build something that can win the competition it&amp;#8217;s probably better to stick to your guns.&lt;/p&gt;
&lt;h3&gt;Good Idea: As Many Plugins As You Can Actually Use&lt;/h3&gt;
&lt;p&gt;Ruby and Rails provide some of the most powerful collections of reliable code that you could hope for. We were originally planning to go 100% with CouchDB for the project, but when it became apparent that we would have to roll our own OpenID authentication we decided to slap MySQL in as well (only for user models) so that we could make use of &lt;a href="http://github.com/binarylogic/authlogic"&gt;AuthLogic&lt;/a&gt; and its OpenID extension. This saved us who-knows-how-many hours of work.&lt;/p&gt;
&lt;p&gt;We also used some powerful Javascript libraries to achieve some impressive visual effects quickly and without too much pain. When planning your app, think about what technologies you&amp;#8217;re using and make sure that there is sufficient library support to get you where you need to be in 48 hours.&lt;/p&gt;
&lt;h3&gt;Bad Idea: Plans Are For Sissies&lt;/h3&gt;
&lt;p&gt;This one is somewhat obvious, but it&amp;#8217;s a good idea to have a strong game plan heading into something as time-limited as the Rumble. It was unavoidable in our case as I was on my honeymoon in Paris until (literally) the day before the competition, but planning in advance would have meant that every team member was utilized every moment they were available instead of spending time figuring out who should be doing what.&lt;/p&gt;
&lt;p&gt;That being said, I think there is also value in not planning &lt;strong&gt;too&lt;/strong&gt; much. During the competition there will be times when you see things that work and you need to let the application grow organically instead of mechanistically sticking to your original gameplan.&lt;/p&gt;
&lt;h3&gt;Good Idea: Hang Out In &lt;span class="caps"&gt;IRC&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;#railsrumble&lt;/code&gt; &lt;span class="caps"&gt;IRC&lt;/span&gt; channel was a good place to be throughout the competition. You get direct access to a couple hundred other competitors as well as the organizers of the competition. If GitHub goes down, if there&amp;#8217;s confusion about the rules, you&amp;#8217;ll get your answers in a couple minutes.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also just fun to feel the energy of the competition and everything from &amp;#8220;Got it deployed!&amp;#8221; to &amp;#8220;so much left to do and so little time zomg&amp;#8221;. I wasn&amp;#8217;t able to physically be in the same area as any Rumblers, but I still had a great time and lots of comraderie on the &lt;span class="caps"&gt;IRC&lt;/span&gt; channel.&lt;/p&gt;
&lt;h3&gt;Bad Idea: Last-Minute Anything&lt;/h3&gt;
&lt;p&gt;You will have things to do until the last minute. &lt;strong&gt;Do not do them.&lt;/strong&gt; You will have features you want to implement in the last 2 hours. &lt;strong&gt;Do not implement them.&lt;/strong&gt; You will want to tweak the style, tweak a view, tweak something that seems important (but isn&amp;#8217;t app-crashing) in the last 20 minutes. &lt;strong&gt;Do not do it.&lt;/strong&gt; Last-minute changes that aren&amp;#8217;t to address specific, serious bugs are a terrible idea when you won&amp;#8217;t have a chance to fix new problems you introduce.&lt;/p&gt;
&lt;p&gt;Next year I am going to try to force myself to spend the last 2-3 hours of the competition doing nothing but finding showstoppers on the production site and fixing only those things. Our OpenID flow was damaged in the last hour of the competition (for registration, not login) and we didn&amp;#8217;t catch it until after pencils down. Never again!&lt;/p&gt;
&lt;h3&gt;Best Idea: Compete in the Rumble!&lt;/h3&gt;
&lt;p&gt;All in all, you can&amp;#8217;t go wrong joining in the Rails Rumble. While your family and non-developer friends probably won&amp;#8217;t quite understand what&amp;#8217;s wrong with you (&amp;#8220;You work 40 hours, over a weekend, and don&amp;#8217;t get paid?&amp;#8221;) you will have a blast and will learn a lot about how to build things inside a pressure cooker. I know that I plan to be back for next year&amp;#8217;s Rumble, and my thanks go out to my team and everyone who made it possible!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=rh4LB07GuUQ:mA2A35Tjl6c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=rh4LB07GuUQ:mA2A35Tjl6c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=rh4LB07GuUQ:mA2A35Tjl6c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=rh4LB07GuUQ:mA2A35Tjl6c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/rh4LB07GuUQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/08/24/rumble-post-mortem.html</feedburner:origLink></entry>
 
 <entry>
   <title>Quick Tip: Railsy Array Checks in jQuery</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/scw5kwot6LY/quick-tip-railsy-array-checks-in-jquery.html" />
   <updated>2009-06-19T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/06/19/quick-tip-railsy-array-checks-in-jquery</id>
   <content type="html">&lt;p&gt;I love the &lt;code&gt;any?&lt;/code&gt; and &lt;code&gt;empty?&lt;/code&gt; convenience methods that Rails and Ruby provide, they make conditional statements much easier to read. I also really dislike the default method of checking this behavior in jQuery:&lt;/p&gt;
&lt;pre name='code' class='js'&gt;if ($('some.element').length &amp;gt; 0) {
  // ...do something
}&lt;/pre&gt;
&lt;p&gt;Well, luckily jQuery is ridiculously easy to extend, so why not just mix that functionality in with a couple of quick shot plugin methods? Just add this javascript sometime after you include jQuery:&lt;/p&gt;
&lt;pre name='code' class='js'&gt;jQuery.fn.any = function() {
  return (this.length &amp;gt; 0);
}

jQuery.fn.none = function() {
  return (this.length == 0);
}&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s all you have to do! Now we can make the same call as before, but it looks a little cleaner:&lt;/p&gt;
&lt;pre name='code' class='js'&gt;if ($('some.element').any()) {
  // do something more readably...
}&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;:&lt;/strong&gt; Apologies, I added in the &lt;code&gt;empty&lt;/code&gt; bit as a last-second update to the post and forgot to check and realize that &lt;code&gt;empty()&lt;/code&gt; is part of jQuery core. Updated the name to &lt;code&gt;none&lt;/code&gt; instead.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=scw5kwot6LY:lhVh-bxFluU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=scw5kwot6LY:lhVh-bxFluU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=scw5kwot6LY:lhVh-bxFluU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=scw5kwot6LY:lhVh-bxFluU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/scw5kwot6LY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/06/19/quick-tip-railsy-array-checks-in-jquery.html</feedburner:origLink></entry>
 
 <entry>
   <title>Make it so with RSpec Macros</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/CI040J5pckk/make-it-so-with-rspec-macros.html" />
   <updated>2009-05-15T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/05/15/make-it-so-with-rspec-macros</id>
   <content type="html">&lt;p&gt;So I had heard a number of times about writing RSpec macros (like those in the fantastic &lt;a href="http://github.com/carlosbrando/remarkable"&gt;Remarkable&lt;/a&gt; library) to ease spec writing for repetitive tasks, but the whole process seemed like more effort than it was worth. Not the case! It&amp;#8217;s actually quite easy to write and include macros for your specs to do some of the standard heavy lifting.&lt;/p&gt;
&lt;p&gt;First of all, &lt;a href="http://www.benmabey.com/2008/06/08/writing-macros-in-rspec/"&gt;this is a great resource&lt;/a&gt; to get started with how to write the actual macros (or custom matchers) themselves. What tripped me up was how to actually include them in my examples; monkeypatching is never a clean process and even though I knew from the comments on that post that there was a public &lt;span class="caps"&gt;API&lt;/span&gt; for doing it, as with many things about RSpec how to do it didn&amp;#8217;t seem immediately obvious.&lt;/p&gt;
&lt;p&gt;In my case, I was looking to define a quick &lt;code&gt;login!&lt;/code&gt; macro that would allow me to easily create a before block to log in as a specified user or just as a FactoryGirl generated one in a &lt;a href="http://github.com/mbleigh/twitter-auth"&gt;TwitterAuth&lt;/a&gt; based app. Here&amp;#8217;s the module I wrote and stuck in my &lt;code&gt;spec_helper.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre class='code' name='ruby'&gt;module LoginMacro
  def login!(user=Factory(:user))
    before do
      @current_user = user
      controller.stub!(:current_user).and_return(@current_user)
      session[:user_id] = @current_user.id
    end
  end
end&lt;/pre&gt;
&lt;p&gt;So that was relatively straightforward and now what I wanted to be able to do was call it in my controller specs like this:&lt;/p&gt;
&lt;pre class='code' name='ruby'&gt;describe UsersController do
  describe "#create" do
    login!
    
    it 'should etc. etc.'
  end
end&lt;/pre&gt;
&lt;p&gt;As it turns out, RSpec offers the ability to add macros and matchers via the &lt;code&gt;config.extend&lt;/code&gt; and &lt;code&gt;config.include&lt;/code&gt; methods on the RSpec &lt;a href="http://gitrdoc.com/rdoc/dchelimsky/rspec/cdbdeef23f3496d81799bebfd2091f0d73084138/classes/Spec/Runner/Configuration.html"&gt;configuration object&lt;/a&gt; (extend is for class-level macros like the one I wrote here, include is for instance-level matchers). You just have to add this to your spec helper&amp;#8217;s configuration portion:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;config.extend(LoginMacro)&lt;/pre&gt;
&lt;p&gt;Voila! Now your specs will be able to use the &lt;code&gt;login!&lt;/code&gt; macro to set up a user in no time. This really wasn&amp;#8217;t any kind of grand discovery or new trick that people experienced with RSpec don&amp;#8217;t already know, but I find that certain things can be hard to come across if you don&amp;#8217;t already know how to use them so I thought I&amp;#8217;d blog for the benefit of others like me.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=CI040J5pckk:BOy_ex7mnyc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=CI040J5pckk:BOy_ex7mnyc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=CI040J5pckk:BOy_ex7mnyc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=CI040J5pckk:BOy_ex7mnyc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/CI040J5pckk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/05/15/make-it-so-with-rspec-macros.html</feedburner:origLink></entry>
 
 <entry>
   <title>TwitterAuth Supports 'Sign in with Twitter'</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/C_ITXbgaIV8/twitter-auth-supports-sign-in-with-twitter.html" />
   <updated>2009-04-17T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/04/17/twitter-auth-supports-sign-in-with-twitter</id>
   <content type="html">&lt;p&gt;Twitter recently implemented &lt;a href="http://apiwiki.twitter.com/Sign-in-with-Twitter"&gt;Sign in with Twitter&lt;/a&gt;, a convenience layer on top of their OAuth solution that provides a better user experience for those making use of OAuth as a sign-in strategy for their applications. I have just added support for this new feature to &lt;a href="http://mbleigh.com/twitter-auth"&gt;TwitterAuth&lt;/a&gt;. This is available immediately to new applications made with TwitterAuth as the default implementation.&lt;/p&gt;
&lt;p align='center'&gt;&lt;img src="http://apiwiki.twitter.com/f/1239839565/sign_in_with_twitter.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;If you already have a TwitterAuth application that you would like to utilize the new sign in method all you need to do is add one line to each of your &lt;code&gt;twitter_auth.yml&lt;/code&gt; environments:&lt;/p&gt;
&lt;pre name='code' class='yaml'&gt;authorize_path: "/oauth/authenticate"&lt;/pre&gt;
&lt;p&gt;You don&amp;#8217;t need to reset any user data or make any other changes, and when you restart your server people should be able to take advantage of the new experience. Enjoy!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=C_ITXbgaIV8:oZ8ZBSMD4GI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=C_ITXbgaIV8:oZ8ZBSMD4GI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=C_ITXbgaIV8:oZ8ZBSMD4GI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=C_ITXbgaIV8:oZ8ZBSMD4GI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/C_ITXbgaIV8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/04/17/twitter-auth-supports-sign-in-with-twitter.html</feedburner:origLink></entry>
 
 <entry>
   <title>Present.ly Nominated for the WebWare 100</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/mWeZQR0yJdg/presently-nominated-for-webware-100.html" />
   <updated>2009-03-31T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/03/31/presently-nominated-for-webware-100</id>
   <content type="html">&lt;div style='float: right;'&gt;&lt;a href="http://www.cnet.com/html/ww/100/2009/poll/communication.html"&gt;&lt;img src="http://www.cnet.com/html/ww/100/2009/images/voteforus/webware100-09_vote_l.jpg" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Intridea&amp;#8217;s &lt;a href="http://www.presentlyapp.com"&gt;Present.ly&lt;/a&gt; has been nominated as a finalist in the &lt;a href="http://www.cnet.com/html/ww/100/2009/poll/communication.html"&gt;WebWare 100 Communication Category&lt;/a&gt;. We&amp;#8217;re honored to be chosen from a pool of more than 5,000 applicants to be one of the 300 finalists to compete for the title.&lt;/p&gt;
&lt;p&gt;The WebWare 100 is a yearly contest held by &lt;span class="caps"&gt;CNET&lt;/span&gt; that allows the public to pick what the 100 best web applications of the year are. Past winners included such products as GMail and Amazon MP3, so we&amp;#8217;re very excited to be included as a finalist for this year&amp;#8217;s selection.&lt;/p&gt;
&lt;p&gt;Voting is open right now, so please &lt;a href="http://www.cnet.com/html/ww/100/2009/poll/communication.html"&gt;vote for us&lt;/a&gt;! Intridea and Present.ly are the reason that I get to make cool open-source stuff for the community, so please help me out and show your support!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=mWeZQR0yJdg:O0z0haCX0_M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=mWeZQR0yJdg:O0z0haCX0_M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=mWeZQR0yJdg:O0z0haCX0_M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=mWeZQR0yJdg:O0z0haCX0_M:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/mWeZQR0yJdg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/03/31/presently-nominated-for-webware-100.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using Git Submodules for Shared Application Components</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/LSiU60Htthk/using-git-submodules-for-shared-application-components.html" />
   <updated>2009-03-25T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/03/25/using-git-submodules-for-shared-application-components</id>
   <content type="html">&lt;p&gt;In some cases you may have the need to run multiple Rails applications with shared functionality. While Rails 3 promises to bring &amp;#8220;mounting apps in apps&amp;#8221; and the ability to make the whole process simple, for now we&amp;#8217;re stuck in the real world. However, it is possible to share components. This post will walk you through how to set up shared  components that live in multiple Rails applications at once and even run specs properly.&lt;/p&gt;
&lt;p&gt;A few notes before we begin:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;This post focuses on models but the same could be applied to controllers, views, and more.&lt;/li&gt;
	&lt;li&gt;I use &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; so the testing solutions come from that perspective.&lt;/li&gt;
	&lt;li&gt;My applications share a database, so I keep all of the migrations in one app and load from a duplicated &lt;code&gt;schema.rb&lt;/code&gt; in the other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Setting Up Your Application&lt;/h3&gt;
&lt;p&gt;First, you&amp;#8217;ll need to create your shared directory. I&amp;#8217;m mounting all shared components to my &lt;code&gt;RAILS_ROOT/shared&lt;/code&gt; directory. So if I have &lt;code&gt;app1&lt;/code&gt; and &lt;code&gt;app2&lt;/code&gt; then I&amp;#8217;ll do this in &lt;code&gt;app1&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code'&gt;mkdir shared
cd shared
touch README
git init
git add .
git commit -m "Initial import of shared repository."
git remote add origin git@some.git:repository/online.git
git push&lt;/pre&gt;
&lt;p&gt;At this point all we&amp;#8217;ve actually done is create a git repository inside our &lt;code&gt;app1&lt;/code&gt; application in the &lt;code&gt;shared&lt;/code&gt; directory and pushed it (with an empty &lt;span class="caps"&gt;README&lt;/span&gt; file) to a remote git repository.&lt;/p&gt;
&lt;p&gt;What we need to do now is actually delete this git repository and re-add it as a submodule from the remote source (this is from the root of &lt;code&gt;app1&lt;/code&gt; again):&lt;/p&gt;
&lt;pre name='code'&gt;git submodule add git@some.git:repository/online.git shared
git submodule init
git add .
git commit -m "Added shared directory as submodule"&lt;/pre&gt;
&lt;p&gt;What we did here is add the repository as a submodule using the &lt;code&gt;git submodule&lt;/code&gt; command. We then ran &lt;code&gt;git submodule init&lt;/code&gt; to update our &lt;code&gt;.git/config&lt;/code&gt; to reflect the new submodule.&lt;br /&gt;
Finally we committed our changes.&lt;/p&gt;
&lt;p&gt;So now we have a submodule living in our application directory, but right now it&amp;#8217;s empty and Rails doesn&amp;#8217;t know or care about it! Next we&amp;#8217;ll set up Rails to make use of the components in the shared directory.&lt;/p&gt;
&lt;h3&gt;Setting Up Rails To Use Shared Components&lt;/h3&gt;
&lt;p&gt;Lets say that we&amp;#8217;re going to create a shared model, &lt;code&gt;SharedModel&lt;/code&gt;. We need to put it in the shared directory but still have it picked up by Rails&amp;#8217;s lazy class loader. So in &lt;code&gt;config/environment.rb&lt;/code&gt; you&lt;br /&gt;
will need to add the following:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;config.load_paths += %W( #{RAILS_ROOT}/shared/models )&lt;/pre&gt;
&lt;p&gt;This tells Rails to look for classes in the shared models path. Now we create our model by creating &lt;code&gt;shared/models/shared_model.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;class SharedModel &amp;lt; ActiveRecord::Base

end&lt;/pre&gt;
&lt;p&gt;When creating shared components I tend not to use Rails&amp;#8217;s model generator, preferring instead to create the class by hand and generate a migration separately in my migration-having app.&lt;/p&gt;
&lt;p&gt;This is actually all you need to do to get your shared components running in Rails. Next we&amp;#8217;ll set up &lt;code&gt;app2&lt;/code&gt; to use the same code!&lt;/p&gt;
&lt;h3&gt;Setting Up The Second Application&lt;/h3&gt;
&lt;p&gt;To set up the second application, you basically need to simply repeat the same steps you did for the first application starting with &lt;code&gt;git submodule add&lt;/code&gt;. So that would be:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Add the submodule and initialize it.&lt;/li&gt;
	&lt;li&gt;Add the shared directory to the load paths in &lt;code&gt;config/environment.rb&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a note, if you are doing this to an existing application with multiple developers, other developers will simply need to pull from your main application once you&amp;#8217;ve pushed it to a remote and run:&lt;/p&gt;
&lt;pre&gt;git submodule init
git submodule update&lt;/pre&gt;
&lt;p&gt;To get the latest revision of the submodule locally for themselves.&lt;/p&gt;
&lt;h3&gt;Changing Shared Components&lt;/h3&gt;
&lt;p&gt;To modify shared components, just change them like you would normal files in your repository. The only difference is that when you want to commit changes you will need to do so from the shared directory, push &lt;strong&gt;and then&lt;/strong&gt; make a new commit from the root directory. This way you are telling the root repository to track a new revision of the&lt;br /&gt;
submodule.&lt;/p&gt;
&lt;h3&gt;Testing Shared Components&lt;/h3&gt;
&lt;p&gt;So just because we&amp;#8217;re sharing components doesn&amp;#8217;t mean that we want to abandon &lt;strong&gt;&lt;span class="caps"&gt;TDD&lt;/span&gt;&lt;/strong&gt;, does it? In fact, it brings up a somewhat interesting problem. I want to have specs that I can run for the shared components that can run in both applications, in fact I want these specs to run in both applications to make sure that the shared components aren&amp;#8217;t&lt;br /&gt;
having any compatibility issues. While this isn&amp;#8217;t extremely difficult to set up, it&amp;#8217;s not easy, either.&lt;/p&gt;
&lt;p&gt;The first step is to create a &lt;code&gt;spec&lt;/code&gt; directory inside your shared submodule, and create a &lt;code&gt;spec_helper.rb&lt;/code&gt; that simply points back out to the root application&amp;#8217;s.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;shared/spec/spec_helper.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;require File.dirname(__FILE__) + '/../../spec/spec_helper'&lt;/pre&gt;
&lt;p&gt;We also need to create a pending spec for our SharedModel to make sure that these are running. In &lt;code&gt;shared/spec/models/shared_model_spec.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;require File.dirname(__FILE__) + '/../spec_helper'

describe SharedModel do
  it 'should have a pending spec'
end&lt;/pre&gt;
&lt;p&gt;The good news is that if you run &lt;code&gt;autospec&lt;/code&gt; from your &lt;code&gt;shared&lt;/code&gt; directory, you should be able to see your pending spec run (you will need to create a second &lt;code&gt;spec.opts&lt;/code&gt; file in the &lt;code&gt;shared/spec&lt;/code&gt; directory for this to use your preferred options). You should push out the changes in your shared directory and get all of your applications up to date. The bad news is that this is the &lt;strong&gt;only&lt;/strong&gt; place your specs will run at the moment. Let&amp;#8217;s change that for the better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You will need to perform the following steps in &lt;b&gt;each&lt;/b&gt; of your Rails apps that use the shared components.&lt;/p&gt;
&lt;p&gt;First to get your specs running with &lt;code&gt;rake spec&lt;/code&gt; we will need to modify the task found in &lt;code&gt;lib/tasks/rspec.rake&lt;/code&gt; by performing the following substitution:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;# When you see this...
FileList['spec/**/*/*_spec.rb']

# Change it to this...
FileList['spec/**/*/*_spec.rb', 'shared/spec/**/*/*_spec.rb']&lt;/pre&gt;
&lt;p&gt;That takes care of the spec rake tasks, but there&amp;#8217;s still the matter of autotesting from your application root. This requires a custom &lt;code&gt;.autotest&lt;/code&gt; file in your application root that looks like this:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;Autotest.add_hook :initialize do |autotest|
  autotest.add_mapping(%r%^shared/models/.*\.rb$%) { |_, m|
    autotest.files_matching %r%^shared/spec/.*_spec.rb$%
  }
end&lt;/pre&gt;
&lt;p&gt;This will automatically pick up changes to your shared models and re-run the specs for all of your shared models when they change. You could get more granular than this, but that&amp;#8217;s a topic for another day.&lt;/p&gt;
&lt;h3&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;Now that all of this is done you should be able to freely develop models in the shared directory and have them completely integerated into your normal development workflow. It&amp;#8217;s quite a bit of work, but once you iron out the kinks it runs beautifully!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=LSiU60Htthk:Ko5u6HmrAEE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=LSiU60Htthk:Ko5u6HmrAEE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=LSiU60Htthk:Ko5u6HmrAEE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=LSiU60Htthk:Ko5u6HmrAEE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/LSiU60Htthk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/03/25/using-git-submodules-for-shared-application-components.html</feedburner:origLink></entry>
 
 <entry>
   <title>TwitterAuth: For Near-Instant Twitter Apps</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/-015JcMb2t4/twitter-auth-for-instant-twitter-apps.html" />
   <updated>2009-03-23T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/03/23/twitter-auth-for-instant-twitter-apps</id>
   <content type="html">&lt;div style='float: right; margin-left: 10px; margin-bottom: 10px'&gt;&lt;img src='http://img.skitch.com/20090320-x339jfeehaeftua1sysax3wsrj.jpg' alt='TwitterAuth'/&gt;&lt;/div&gt;
&lt;p&gt;The public beta of Twitter OAuth support &lt;a href="http://news.cnet.com/8301-17939_109-10197898-2.html?part=rss&amp;amp;tag=feed&amp;amp;subj=Webware"&gt;has been released&lt;/a&gt; and I&amp;#8217;m excited to introduce a new library that I&amp;#8217;ve been working on called &lt;strong&gt;TwitterAuth&lt;/strong&gt;. TwitterAuth is a Rails plugin that provides a full external authentication stack for Rails applications utilizing Twitter. Think of it as &amp;#8220;Twitter Connect&amp;#8221; for Rails, letting you create an application that may be logged into using only Twitter credentials.&lt;/p&gt;
&lt;p&gt;TwitterAuth supports both &lt;strong&gt;OAuth&lt;/strong&gt; and &lt;strong&gt;&lt;span class="caps"&gt;HTTP&lt;/span&gt; Basic&lt;/strong&gt; (though OAuth is certainly the recommended strategy) giving you maximum flexibility for building the application. Without further ado, let&amp;#8217;s get into the installation and usage of TwitterAuth!&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;TwitterAuth is available as a GemPlugin, so the preferred way to install it is simply to add it as a dependency in your &lt;code&gt;config/environment.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;config.gem 'twitter-auth', :lib =&amp;gt; 'twitter_auth'&lt;/pre&gt;
&lt;p&gt;You can also choose to install it as a traditional Rails plugin:&lt;/p&gt;
&lt;pre name='code'&gt;script/plugin install git://github.com/mbleigh/twitter-auth.git&lt;/pre&gt;
&lt;p&gt;Once you&amp;#8217;ve installed it, you&amp;#8217;re ready to create a new application using TwitterAuth!&lt;/p&gt;
&lt;h3&gt;The Low-Down&lt;/h3&gt;
&lt;p&gt;TwitterAuth uses Rails 2.3 Engine support to completely encapsulate the login process within itself. All you need to do is run a generator to make all of the support files necessary in your application. Run it with the &lt;code&gt;--basic&lt;/code&gt; option if you want to use &lt;span class="caps"&gt;HTTP&lt;/span&gt; Basic, otherwise it will default to OAuth.&lt;/p&gt;
&lt;pre&gt;script/generate twitter_auth&lt;/pre&gt;
&lt;p&gt;This generates a User class, a migration, and &lt;code&gt;twitter_auth.yml&lt;/code&gt;. You will need to edit &lt;code&gt;twitter_auth.yml&lt;/code&gt; to match the settings of your application, such as providing the OAuth client token and secret.&lt;/p&gt;
&lt;p&gt;Once you&amp;#8217;ve migrated, that&amp;#8217;s it! You are up and running with Twitter authentication; just point users at &lt;code&gt;/login&lt;/code&gt; to start the process (login and registration are handled in a single step). For more detailed usage information including how to access the Twitter &lt;span class="caps"&gt;API&lt;/span&gt; through TwitterAuth, take a look at &lt;a href="http://github.com/mbleigh/twitter-auth"&gt;the &lt;span class="caps"&gt;README&lt;/span&gt; file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The source for TwitterAuth is &lt;a href="http://github.com/mbleigh/twitter-auth"&gt;available on GitHub&lt;/a&gt;. I have also created a &lt;a href="http://mbleigh.lighthouseapp.com/projects/27783-twitterauth"&gt;Lighthouse Project&lt;/a&gt; for the reporting of any bugs you may come across. There is also a &lt;a href="http://mbleigh.com/twitter-auth/"&gt;basic homepage&lt;/a&gt; that will be listing who&amp;#8217;s using TwitterAuth.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re pretty familiar with Rails authentication systems (particularly &lt;a href="http://github.com/technoweenie/restful-authentication"&gt;Restful Authentication&lt;/a&gt;), this is probably all you need to know to get started. Go forth and make awesome apps! If not, I&amp;#8217;ve written a quick run-through of the whole process to make it easy for &lt;strong&gt;anyone&lt;/strong&gt; to get started with Twitter apps.&lt;/p&gt;
&lt;h3&gt;A Quick Run-Through&lt;/h3&gt;
&lt;p&gt;I think the best way to show what TwitterAuth is capable of is just to show how quickly you can build a simple Twitter application with it. To that end, let&amp;#8217;s build a simple way to look at your friends&amp;#8217; timeline in an old-school text-based way (note, this is a totally useless application but works well for a quick demo). First we need to generate the app:&lt;/p&gt;
&lt;pre&gt;rails texty-twitter&lt;/pre&gt;
&lt;p&gt;Next we want to install TwitterAuth on the application, so we&amp;#8217;ll add this to our &lt;code&gt;config/environment.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;config.gem 'twitter-auth', :lib =&amp;gt; 'twitter_auth'&lt;/pre&gt;
&lt;p&gt;Once we have hooked TwitterAuth into the application, we will want to run the generator to build the support files we need:&lt;/p&gt;
&lt;pre&gt;script/generate twitter_auth --oauth&lt;/pre&gt;
&lt;p&gt;Before I start on application logic I always lay out a basic &lt;span class="caps"&gt;HTML&lt;/span&gt; layout. Here it is for this application (in &lt;code&gt;app/views/layouts/master.html.erb&lt;/code&gt;):&lt;/p&gt;
&lt;pre name='code' class='html'&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;style type='text/css'&amp;gt;
      ul.tweets {
        list-style: none;
        margin: 0;
        padding: 0;
      }

      ul.tweets li {
        font-family: monospace;
        font-size: 14px;
        padding: 4px 8px;
      }

      ul.tweets li a {
        color: #fa0;
        font-weight: bold;
        text-decoration: none;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;p&gt;The next step is to edit &lt;code&gt;config/twitter_auth.yml&lt;/code&gt; to reflect our OAuth client key and secret (to register your application log in to Twitter and visit &lt;a href="http://twitter.com/oauth_clients"&gt;http://twitter.com/oauth_clients&lt;/a&gt;). Other than the client key and secret, the defaults are fine for our purposes. We&amp;#8217;ve now set up a basic TwitterAuth application; that&amp;#8217;s really all there is to it. So now let&amp;#8217;s make it a &lt;strong&gt;working&lt;/strong&gt; Twitter application. First let&amp;#8217;s generate a controller:&lt;/p&gt;
&lt;pre&gt;script/generate controller timeline&lt;/pre&gt;
&lt;p&gt;This will just be a one-action controller that will render out the main timeline for the logged in user in an text-based manner. Here&amp;#8217;s the contents of the controller:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;class TimelineController &amp;lt; ApplicationController
  # this requires us to log in through Twitter before accessing any actions here
  before_filter :login_required

  def index  
    @tweets = current_user.twitter.get('/statuses/friends_timeline')
  end
end&lt;/pre&gt;
&lt;p&gt;In this action, &lt;code&gt;current_user&lt;/code&gt; is the logged in user, and the &lt;code&gt;twitter&lt;/code&gt; method provides a simple wrapper around the &lt;a href="http://apiwiki.twitter.com/REST+API+Documentation"&gt;Twitter &lt;span class="caps"&gt;REST&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; that will automatically parse &lt;span class="caps"&gt;JSON&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt; requests into Ruby hashes for you to use in your application. So &lt;code&gt;current_user.twitter.get('/statuses/friends_timeline')&lt;/code&gt; will grab the latest statuses from your friends&amp;#8217; timeline (the main timeline you see when you&amp;#8217;re logged in to Twitter) as an array of hashes. Now let&amp;#8217;s display the tweets by creating &lt;code&gt;app/views/timeline/index.html.erb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='html'&gt;&amp;lt;ul class='tweets'&amp;gt;
  &amp;lt;% for tweet in @tweets %&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;%= link_to tweet['user']['screen_name'] + ':', 'http://twitter.com/' + tweet['user']['screen_name'], :target =&amp;gt; '_blank' %&amp;gt; &amp;lt;%= tweet['text'] %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
&lt;p&gt;This simply goes through each of the tweets we pulled down and adds a list item with a link to the author of the tweet and the content of the tweet. The structure of the hashes are identical to their description in the &lt;a href="http://apiwiki.twitter.com/REST+API+Documentation#ReturnElements"&gt;Return Elements section of the Twitter &lt;span class="caps"&gt;API&lt;/span&gt; wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we need to add some routing to tie everything together. Make the &lt;code&gt;config/routes.rb&lt;/code&gt; look like this:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;ActionController::Routing::Routes.draw do |map|
  map.root :controller =&amp;gt; 'stream', :action =&amp;gt; 'index'
end&lt;/pre&gt;
&lt;p&gt;And we&amp;#8217;re done! Fire up your server with &lt;code&gt;script/server&lt;/code&gt; and go to &lt;code&gt;http://localhost:3000/&lt;/code&gt;. If everything is working properly, it should redirect you to Twitter with a screen like this:&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="http://img.skitch.com/20090320-qwxf5rnn4qs75a7xbwccsppgam.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Once you click through and hit allow, it should then take you back and display your tweet stream in an old-school text interface, something like this:&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="http://img.skitch.com/20090321-nefkuh6xdq3jx8wejg8a11hsew.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a simple and useless application, but in about 10-15 minutes you&amp;#8217;ve created a fully-functioning Rails application that accesses the Twitter &lt;span class="caps"&gt;API&lt;/span&gt; and stores user information. Not bad!&lt;/p&gt;
&lt;h3&gt;See You At RailsConf!&lt;/h3&gt;
&lt;p&gt;&lt;a href='http://en.oreilly.com/rails2009/public/schedule/detail/8517' target='_blank'&gt;&lt;img src="http://assets.en.oreilly.com/1/event/24/rails2009_banner_speaking_210x60.jpg" width="210" height="60"  border="0"  alt="RailsConf 2009" title="RailsConf 2009" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TwitterAuth is a big part of what I will be talking about at RailsConf in my session &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/8517"&gt;&amp;#8216;Twitter on Rails&amp;#8217;&lt;/a&gt;. if you&amp;#8217;re interested in the plugin and attending RailsConf in May I hope you&amp;#8217;ll stop by; I&amp;#8217;ll be building an entire Twitter application from scratch during the 45 minute presentation. Also, feel free to &lt;a href="http://twitter.com/mbleigh"&gt;follow me on Twitter&lt;/a&gt; if you&amp;#8217;re so inclined.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=-015JcMb2t4:b0f8fz-fFH4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=-015JcMb2t4:b0f8fz-fFH4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=-015JcMb2t4:b0f8fz-fFH4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=-015JcMb2t4:b0f8fz-fFH4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/-015JcMb2t4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/03/23/twitter-auth-for-instant-twitter-apps.html</feedburner:origLink></entry>
 
 <entry>
   <title>Yet Another Twitter Monetization Strategy: 'Claimed' Hashtags</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/8pgUcurDROE/another-twitter-monetization-idea.html" />
   <updated>2009-03-18T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2009/03/18/another-twitter-monetization-idea</id>
   <content type="html">&lt;p&gt;So everyone and their cat have made predictions about how &lt;a href="http://www.twitter.com/"&gt;Twitter&lt;/a&gt; will and could monetize (what, you haven&amp;#8217;t heard of Sprinkles the economic forecasting cat?). I have one more idea, but it&amp;#8217;s not because I think that this necessarily will happen so much as because I think it would be a fantastic feature to have for businesses on Twitter. The concept is &amp;#8216;claiming&amp;#8217; a hash tag.&lt;/p&gt;
&lt;p&gt;Now the main Twitter interface pretty much ignores hash tags, but &lt;a href="http://search.twitter.com/"&gt;Twitter Search&lt;/a&gt; does not and I see it as a given that hash tags are here to stay. So for hash tags that have to do with an event, a company, or other kinds of definable entities there should be a special text advertising block that can be purchased at the top of the tag search that will allow the entity that the tag is about to explain and maybe provide a few links.&lt;/p&gt;
&lt;p&gt;For example, with all of the &lt;a href="http://search.twitter.com/search?q=sxsw"&gt;endless tweets about &lt;span class="caps"&gt;SXSW&lt;/span&gt;&lt;/a&gt; I think it would be useful both for the &lt;span class="caps"&gt;SXSW&lt;/span&gt; organizers &lt;strong&gt;and for the people looking at the tag&lt;/strong&gt; to have a block at the top that says something along the lines of &amp;#8220;&lt;span class="caps"&gt;SXSW&lt;/span&gt; is a conference held yearly in Austin, TX that encompasses video, audio, and interactive media&amp;#8221; with a couple of links to pertinent information. This provides a context to people clicking through to the Twitter Trends #&lt;span class="caps"&gt;SXSW&lt;/span&gt; tag who wouldn&amp;#8217;t otherwise know much about the conference and gives &lt;span class="caps"&gt;SXSW&lt;/span&gt; another way to promote themselves.&lt;/p&gt;
&lt;p&gt;This system would have to have some pretty stringent acceptance requirements, you wouldn&amp;#8217;t want competitors to be able to claim their opponent&amp;#8217;s tags etc. but I also think it has a lot of promise for providing a revenue stream for Twitter and actually useful information for users. I&amp;#8217;m not a market prognosticator, and I think it&amp;#8217;s actually pretty unlikely that this would come to pass, but I do think that it would be an interesting new way to advertise on the web.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=8pgUcurDROE:tlVGjtIGPcM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=8pgUcurDROE:tlVGjtIGPcM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=8pgUcurDROE:tlVGjtIGPcM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=8pgUcurDROE:tlVGjtIGPcM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/8pgUcurDROE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/03/18/another-twitter-monetization-idea.html</feedburner:origLink></entry>
 
 <entry>
   <title>The Case For GitHub Canonization</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/fiSP9TylF6M/the-case-for-github-canonization.html" />
   <updated>2009-03-03T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/03/03/the-case-for-github-canonization</id>
   <content type="html">&lt;p&gt;I was going through the fork queue of one of my projects on GitHub today when it really struck me how useful it would be to have canonical projects in GitHub. Now, I know that to some extent canonization (by which I mean an &amp;#8216;official&amp;#8217; version of a given project that would be accessible at, say, http://github.com/project-name instead of http://github.com/user-name/project-name) goes against the &amp;#8216;free forking spirit&amp;#8217; of Git and GitHub, but I believe that the benefits would outweigh the potential risks.&lt;/p&gt;
&lt;p&gt;If GitHub provided a canonization process, I would imagine it would work (something) like this:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A user creates a project. Until otherwise noted, it lives at http://github.com/user-name/project-name&lt;/li&gt;
	&lt;li&gt;A user chooses a button somewhere in admin that says &amp;#8220;canonize.&amp;#8221; Click!&lt;/li&gt;
	&lt;li&gt;GitHub examines the project and checks to see if the canonical name already exists and also &lt;strong&gt;if the project is the &amp;#8216;root&amp;#8217; of the most forks&lt;/strong&gt;.&lt;/li&gt;
	&lt;li&gt;If there is no canonical conflict (no project exists and the specified project is the root of most forks), canonical status is granted.&lt;/li&gt;
	&lt;li&gt;If there is a canonical conflict (a non-root fork, for instance), the canonization is marked as &amp;#8216;pending&amp;#8217; and a message is sent to the root fork asking if the fork can canonize.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now this isn&amp;#8217;t dead simple and it could be abused (&amp;#8216;canon&amp;#8217; squatting for projects etc.) which I imagine is most of the reason GitHub is hesitant to implement it. It might require some kind of administrative approval process to prevent such abuse, which is both more work and can cause conflict. The benefits of such a system, however, are many.&lt;/p&gt;
&lt;p&gt;Canon allows for the GitHub gem server to provide the &amp;#8216;official&amp;#8217; gem for a project without all of the messy remembering of user names. This would obviate the need for RubyForge entirely, something that I suspect may get &lt;a href="http://judofyr.net/"&gt;Magnus Holm&lt;/a&gt; to argue with me (again). GitHub is where open-source development in Ruby is happening now, it may as well be where we get our gems. If I can bump my gemspec and that&amp;#8217;s all I have to do to distribute the latest official version of my gem, that saves me time and effort.&lt;/p&gt;
&lt;p&gt;Canon also allows for projects such as Jamis Buck&amp;#8217;s Capistrano and FuzzyFinderTextMate to live on after their creators have officially given up on them. If I have a project that I don&amp;#8217;t have time to maintain, I can &amp;#8216;pass the torch&amp;#8217; to another fork of the project which would then become canon.&lt;/p&gt;
&lt;p&gt;Finally, canon makes it easier for people to figure out which fork of a project to contribute pull requests. This is a rarer case, but there are some times when it can be difficult to tell who the real maintainer of a project might be. Canonization makes this easy.&lt;/p&gt;
&lt;p&gt;None of this has to conflict with GitHub&amp;#8217;s existing system: you should still be able to pull projects and install gems from the user-name/project-name nomenclature as before. Canonization would simply add a new layer of usefulness to the already crazy-useful site. So how about it, GitHubbers?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=fiSP9TylF6M:2n3OX8KKUR0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=fiSP9TylF6M:2n3OX8KKUR0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?i=fiSP9TylF6M:2n3OX8KKUR0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/mbleigh?a=fiSP9TylF6M:2n3OX8KKUR0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/mbleigh?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/fiSP9TylF6M" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/03/03/the-case-for-github-canonization.html</feedburner:origLink></entry>
 
 <entry>
   <title>Quick Tip: Rails URL Validation</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/6gbWgAufiU8/quick-tip-rails-url-validation.html" />
   <updated>2009-02-18T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/18/quick-tip-rails-url-validation</id>
   <content type="html">&lt;p&gt;After doing a quick &lt;a href="http://www.google.com/search?q=rails+url+validation&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t&amp;amp;rls=org.mozilla:en-US:official&amp;amp;client=firefox-a"&gt;Google Search&lt;/a&gt; I realized that everyone might not know about a great way to do &lt;span class="caps"&gt;URL&lt;/span&gt; validation in Rails. The secret is a little-known method of the &lt;code&gt;URI&lt;/code&gt; class, &lt;code&gt;regexp&lt;/code&gt;. It lets you generate a regular expression for matching URLs based on an array of accepted protocols. What&amp;#8217;s even better, it can be plugged directly into Rails&amp;#8217;s &lt;code&gt;validates_format_of&lt;/code&gt;. It&amp;#8217;s this easy:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;class User
  validates_format_of :website, :with =&amp;gt; URI::regexp(%w(http https))
end&lt;/pre&gt;
&lt;p&gt;This will match anything that &lt;code&gt;URI.parse&lt;/code&gt; will recognize, meaning that it&amp;#8217;s a pretty accurate and powerful &lt;span class="caps"&gt;URL&lt;/span&gt; matcher. &lt;span class="caps"&gt;URL&lt;/span&gt; validation was one of those little annoyances in writing Rails models because it really seemed like there should be an easier way. I found mine, so I thought I&amp;#8217;d share it!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=LhHEO3dn"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=xASGyUMB"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=xASGyUMB" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Bb12QlKX"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/6gbWgAufiU8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/18/quick-tip-rails-url-validation.html</feedburner:origLink></entry>
 
 <entry>
   <title>Utilize Canonical URLs in Your Rails Apps</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/f_5vImza3c8/utilize-canonical-urls-in-your-rails-apps.html" />
   <updated>2009-02-13T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/13/utilize-canonical-urls-in-your-rails-apps</id>
   <content type="html">&lt;p&gt;Today came the announcement that all of the major search engines are &lt;a href="http://www.seomoz.org/blog/canonical-url-tag-the-most-important-advancement-in-seo-practices-since-sitemaps"&gt;going to support a &amp;#8216;canonical&amp;#8217; &lt;span class="caps"&gt;URL&lt;/span&gt; hint&lt;/a&gt; that will allow site owners to specify a single &lt;span class="caps"&gt;URL&lt;/span&gt; for content that may be replicated across many URLs (such as for categories etc.).&lt;/p&gt;
&lt;p&gt;To make use of this in Rails applications, I&amp;#8217;ve written a plugin that allows you to easily specify canonical URLs for your content. To install it as a gem, just add this to your &lt;code&gt;environment.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;config.gem 'mbleigh-canonical-url', :source =&amp;gt; 'http://gems.github.com', :lib =&amp;gt; 'canonical_url'&lt;/pre&gt;
&lt;p&gt;Using it is extremely simple; just add this to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of your layout:&lt;/p&gt;
&lt;pre name='code' class='html'&gt;&amp;lt;%= canonical_link_tag %&amp;gt;&lt;/pre&gt;
&lt;p&gt;And in your controllers, any time you want to specify a canonical &lt;span class="caps"&gt;URL&lt;/span&gt; you can do so like this:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;class BlogController &amp;lt; ApplicationController
  def show
    @post = find_post # assume this is a standard blog post type record
    canonical_url blog_post_path(post.year, post.month, post.day, post.slug)
  end
end&lt;/pre&gt;
&lt;p&gt;Now any time the &lt;code&gt;show&lt;/code&gt; action is run, no matter how the routing came to be there, a single canonical &lt;span class="caps"&gt;URL&lt;/span&gt; will be shown in the header. If no canonical &lt;span class="caps"&gt;URL&lt;/span&gt; is specified in the controller (or through the &lt;code&gt;canonical_link_tag&lt;/code&gt; helper directly) the helper will not output anything, making it completely harmless to add to any application.&lt;/p&gt;
&lt;p&gt;The source for the plugin is &lt;a href="http://github.com/mbleigh/canonical-url"&gt;available on GitHub&lt;/a&gt;. So go forth and canonize your applications!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=FKs0QwtC"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=WToxgWK7"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=WToxgWK7" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=mPoBaCg7"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/f_5vImza3c8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/13/utilize-canonical-urls-in-your-rails-apps.html</feedburner:origLink></entry>
 
 <entry>
   <title>Outsource Your Blog</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/IAp9EuOCeBo/outsource-your-blog.html" />
   <updated>2009-02-11T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/11/outsource-your-blog</id>
   <content type="html">&lt;p&gt;Blogs are simple pieces of software. It&amp;#8217;s the penultimate &amp;#8220;sample application&amp;#8221; that you build when learning frameworks like &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt;. But what I&amp;#8217;ve found is, the more familiar I am with writing and managing blogging applications, the less I have any interest in doing it. Everything is too heavyweight, with themes and databases and complex administrative interfaces. I found myself yearning for something simple, uncluttered, and under my control.&lt;/p&gt;
&lt;p&gt;When &lt;a href="http://github.com/blog/272-github-pages"&gt;GitHub announced support for user pages&lt;/a&gt; I knew in the back of my mind that this was going to be a big deal. At the time I didn&amp;#8217;t really know how it could be used for a blog since it seemed to just serve up static pages, but I definitely liked what I was hearing. After a couple of months went by, I finally decided to take the plunge and see what I could accomplish. Surprisingly, everything I wanted in a blog!&lt;/p&gt;
&lt;h3&gt;Dead Simple Publishing&lt;/h3&gt;
&lt;p&gt;GitHub Pages are as simple as:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Create a GitHub repository called yourname.github.com&lt;/li&gt;
	&lt;li&gt;Push a &amp;#8216;master&amp;#8217; branch to that repository&lt;/li&gt;
	&lt;li&gt;GitHub will automatically build your page using &lt;a href="http://github.com/mojombo/jeyll"&gt;Jekyll&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may not have heard of Jekyll before (at least outside of the context of GitHub pages), but it is essentially an &lt;span class="caps"&gt;HTML&lt;/span&gt; generator that allows you to generate static &lt;span class="caps"&gt;HTML&lt;/span&gt; sites based on some very simple rules. Once you learn those rules, it&amp;#8217;s extremely simple to build sites that can be deployed anywhere that can serve up &lt;span class="caps"&gt;HTML&lt;/span&gt; (no server-side required).&lt;/p&gt;
&lt;p&gt;You can also use a &lt;code&gt;CNAME&lt;/code&gt; to redirect your own domain to GitHub.&lt;/p&gt;
&lt;h3&gt;What About Comments? Images?&lt;/h3&gt;
&lt;p&gt;New tools have appeared that not only take care of all of the functionality I need for handling blog comments and image uploads, but do them better than any blog engine I have ever used.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.disqus.com/"&gt;Disqus&lt;/a&gt; completely offloads blog post comments, and does a ridiculously good job of it. You get message threading, a great e-mail notification system, spam protection, and best of all it&amp;#8217;s as simple as a Javascript include in your blog post template.&lt;/p&gt;
&lt;p&gt;Images are easy enough to add to a directory structure, but I find it even easier to use &lt;a href="http://www.skitch.com/"&gt;Skitch&lt;/a&gt;, drag an image to it, webpost it, and then use the direct image &lt;span class="caps"&gt;URL&lt;/span&gt; to embed it in the post.&lt;/p&gt;
&lt;h3&gt;Why Do It?&lt;/h3&gt;
&lt;p&gt;I like using Ruby. I like writing my posts in Textile. I hate managing comments and complicated blog systems. If that sounds like you, you may want to look into outsourcing your own blog.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=7H7jFAeN"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=zbDJmNUf"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=zbDJmNUf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=ZMBwST26"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/IAp9EuOCeBo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/11/outsource-your-blog.html</feedburner:origLink></entry>
 
 <entry>
   <title>Open Source Is Amazing</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/IPzs5YSYNCg/open-source-is-amazing.html" />
   <updated>2009-02-11T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/11/open-source-is-amazing</id>
   <content type="html">&lt;p&gt;Yesterday, I pushed by new, Jekyll-powered blog out to GitHub. That was 24 hours ago. Today, I get a note from Scott Chacon (GitHub guy and overall git guru) saying he liked my template and decided to use it for his site.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s what&amp;#8217;s so great about GitHub&amp;#8217;s open source community: I shared it with no publicity or fanfare on my GitHub account and someone else found it useful and implemented it for their own site. I guess maybe some people don&amp;#8217;t like others copying their site, I think it&amp;#8217;s pretty great!&lt;/p&gt;
&lt;p&gt;So if you like this little blog and open-source project display page, &lt;a href="http://github.com/mbleigh/mbleigh.github.com/"&gt;fork away&lt;/a&gt;! All that I would like in return is for you to let me know that you&amp;#8217;re using it so I can check out your site.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=f5lLHTh4"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=6Q7qshJn"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=6Q7qshJn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=puKx9kq9"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/IPzs5YSYNCg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/11/open-source-is-amazing.html</feedburner:origLink></entry>
 
 <entry>
   <title>Moving to Jekyll</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/4jXwreNAPj8/moving-to-jekyll.html" />
   <updated>2009-02-10T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/10/moving-to-jekyll</id>
   <content type="html">&lt;p&gt;As of today, my blog and site are hosted on &lt;a href="http://github.com/mbleigh/mbleigh.github.com"&gt;GitHub&lt;/a&gt; and served through &lt;a href="http://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt;. I switched to WordPress not too long ago but felt slightly disingenuous not using a Ruby-based solution. I had been using Jekyll for a couple of other projects (&lt;a href="http://www.intrideauniversity.com/"&gt;Intridea University&lt;/a&gt; and my wedding website) and decided to go ahead and go all out.&lt;/p&gt;
&lt;p&gt;The look is mostly the same but I love that I can just pop into TextMate, work on a Textile file, push to GitHub and bam! I&amp;#8217;m deployed. If you haven&amp;#8217;t used the &lt;a href="http://github.com/blog/272-github-pages"&gt;GitHub Pages&lt;/a&gt; feature of GitHub I suggest you give it a try. It&amp;#8217;s great!&lt;/p&gt;
&lt;p&gt;The only downside is that the &lt;span class="caps"&gt;RSS&lt;/span&gt; feed will be resetting all of the unique IDs so you may get your feed reader spammed if you&amp;#8217;re a subscriber. Also the comments are vanished once again (oops!) but I&amp;#8217;m now explicitly setting Disqus permalinks so the next time I change my mind about how I want to run the site hopefully it will be better.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=kPY4tmSy"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=6Stfpj8F"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=6Stfpj8F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=V07nFUTg"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/4jXwreNAPj8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/10/moving-to-jekyll.html</feedburner:origLink></entry>
 
 <entry>
   <title>It's No Joke - Real-Time Search is a Big Deal</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/iw5sWCbjqSg/its-no-joke-real-time-search-is-a-big-deal.html" />
   <updated>2009-02-09T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/09/its-no-joke-real-time-search-is-a-big-deal</id>
   <content type="html">&lt;p&gt;I saw the article &lt;a href="http://lewmoorman.com/googles-first-real-threat-twit"&gt;&amp;#8217;Google&amp;#8217;s First Real Threat: Twitter&amp;#8217;&lt;/a&gt; pop up in my &lt;span class="caps"&gt;RSS&lt;/span&gt; readers today from a couple sources and didn&amp;#8217;t click through and read; I had already learned the power of &lt;a href="http://search.twitter.com/"&gt;Twitter Search&lt;/a&gt; on multiple occasions (see &lt;a href="http://intridea.com/2009/1/22/twitter-search-plus-find-replies-inline-with-twitter-search?blog=company"&gt;my previous discussion here&lt;/a&gt;). But then something funny happened: I got an e-mail from &lt;a href="http://www.oreilly.com/"&gt;O&amp;#8217;Reilly&lt;/a&gt; saying that &lt;strong&gt;all three&lt;/strong&gt; of my &lt;a href="http://www.railsconf.com/"&gt;RailsConf&lt;/a&gt; proposals were accepted. Then I heard from a colleague here at Intridea that his talk was accepted.&lt;/p&gt;
&lt;p&gt;This seemed, frankly, too good to be true. So I hit up Twitter Search for RailsConf, and sure enough, &lt;strong&gt;everyone&lt;/strong&gt; seemed to be elated about getting their proposal(s) accepted. This confirmed my suspicion, and I contacted O&amp;#8217;Reilly immediately. In fact, I contacted O&amp;#8217;Reilly and they weren&amp;#8217;t even aware of the problem yet. I may have been the one who alerted them to the issue in the first place. Confirmation came a few minutes later &lt;a href="https://twitter.com/railsconf/status/1192966267"&gt;via the RailsConf Twitter account&lt;/a&gt;. While I&amp;#8217;m a bit disheartened that I&amp;#8217;m not necessarily speaking at RailsConf, it was an object lesson in just how powerful Twitter search has become.&lt;/p&gt;
&lt;p&gt;Is Twitter a &lt;strong&gt;replacement&lt;/strong&gt; for Google? No. But Twitter provides an instantaneous connection to what is happening to people right now, and in some (many) circumstances it can give you answers that Google never would, even &lt;strong&gt;after&lt;/strong&gt; they re-index the web. This also to me serves as a lesson in how to truly compete with Google. Don&amp;#8217;t try to &amp;#8216;out-Google Google&amp;#8217; like &lt;a href="http://www.cuil.com"&gt;Cuil&lt;/a&gt; did. Instead find a way to provide a search that Google can&amp;#8217;t touch, that can&amp;#8217;t be created simply by crawling the web endlessly looking for new content.&lt;/p&gt;
&lt;p&gt;Pay attention to where Twitter search goes in the coming months and years, because it&amp;#8217;s no joke: real time search is a &lt;strong&gt;big deal&lt;/strong&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=OfsxoDiF"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=dyiIytT0"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=dyiIytT0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=FrTBcLCV"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/iw5sWCbjqSg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/09/its-no-joke-real-time-search-is-a-big-deal.html</feedburner:origLink></entry>
 
 <entry>
   <title>SASS: The Better, More Powerful CSS</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/asyH4mbEwJY/sass-the-better-more-powerful-css.html" />
   <updated>2009-02-04T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/04/sass-the-better-more-powerful-css</id>
   <content type="html">&lt;p&gt;I am a huge fan of &lt;a href="http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html"&gt;&lt;span class="caps"&gt;SASS&lt;/span&gt;&lt;/a&gt; (Syntactically Awesome Stylesheets) for styling Rails applications. I have been using it on all of my projects for quite a while now and have developed some great techniques that make it much easier to organize, write, and read stylesheets in an application.&lt;/p&gt;
&lt;p&gt;Unlike &lt;span class="caps"&gt;HAML&lt;/span&gt;, &lt;span class="caps"&gt;SASS&lt;/span&gt; retains most of the same &amp;#8220;feel&amp;#8221; when writing the code as vanilla &lt;span class="caps"&gt;CSS&lt;/span&gt;. It simply adds more power and better organizational tools, making it an easy choice as a go-to replacement. You can teach someone the basics of &lt;span class="caps"&gt;SASS&lt;/span&gt; in about 30 seconds: use two spaces to indent everything, put the colon before the declaration and no semicolon afterwards. In fact, I&amp;#8217;ve even written regular expressions to convert &lt;span class="caps"&gt;CSS&lt;/span&gt; to &lt;span class="caps"&gt;SASS&lt;/span&gt; mechanically in some cases. It&amp;#8217;s easy to pick up and once you do you will start reaping real benefits.&lt;/p&gt;
&lt;h3&gt;The 20-Second &amp;#8220;Get Up And Running&amp;#8221;&lt;/h3&gt;
&lt;p&gt;To use &lt;span class="caps"&gt;SASS&lt;/span&gt;, you must have the &lt;span class="caps"&gt;HAML&lt;/span&gt; gem installed on your Rails app. Add it to your &lt;code&gt;environment.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;config.gem 'haml', :version =&amp;gt; '&amp;gt;= 2.0.6'&lt;/pre&gt;
&lt;p&gt;Now you can create &lt;span class="caps"&gt;SASS&lt;/span&gt; stylesheets simply by making &lt;code&gt;.sass&lt;/code&gt; files in a &lt;code&gt;public/stylesheets/sass&lt;/code&gt; directory.&lt;/p&gt;
&lt;h3&gt;Basic Example: Building a Menu the &lt;span class="caps"&gt;SASS&lt;/span&gt; Way&lt;/h3&gt;
&lt;p&gt;The best way to start explaining the power of &lt;span class="caps"&gt;SASS&lt;/span&gt; may be through one of the more common styling tasks one encounters: styling a menu. Here we&amp;#8217;ll assume a menu structure like this:&lt;/p&gt;
&lt;pre name='code' class='html'&gt;&amp;lt;ul id='menu'&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href='/'&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href='/about'&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href='/services'&amp;gt;Services&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href='/contact'&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
&lt;p&gt;To style this menu in &lt;span class="caps"&gt;CSS&lt;/span&gt;, we might do something like this:&lt;/p&gt;
&lt;pre name='code' class='css'&gt;#menu {
  margin: 0;
  list-style: none;
}

#menu li {
  float: left;
}

#menu li a {
  display: block;
  float: left;
  padding: 4px 8px;
  text-decoration: none;
  background: #2277aa;
  color: white;
}&lt;/pre&gt;
&lt;p&gt;&lt;span class="caps"&gt;SASS&lt;/span&gt; allows you to use indentation to indicate hierarchy, saving much repetition and space. The same code in &lt;span class="caps"&gt;SASS&lt;/span&gt; looks like this:&lt;/p&gt;
&lt;pre name='code' class='css'&gt;!menu_bg = #2277aa
  
#menu
  :margin 0
  :list-style none
  li
    :float left
    a
      :display block
      :float left
      :padding 4px 8px
      :text-decoration none
      :color white
      :background = !menu_bg&lt;/pre&gt;

&lt;p&gt;Hierarchical selectors mean that if you indent something, the selector it falls under will automatically be prepended to it, so the two examples above generate the same output. You&amp;#8217;ll also notice &lt;code&gt;!menu_bg&lt;/code&gt; in the &lt;span class="caps"&gt;SASS&lt;/span&gt; code. &lt;span class="caps"&gt;SASS&lt;/span&gt; allows you to declare constants that can be reused throughout the code, a very useful feature when dealing with colors.&lt;/p&gt;
&lt;p&gt;Now we have our basic setup for the menu, but let&amp;#8217;s handle some better cases. I want the color to change when I hover over the menu options and I want to highlight the current menu option (we&amp;#8217;ll assume that the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; encapsulating the current menu item will have class &amp;#8216;current&amp;#8217; when it is selected). Let&amp;#8217;s add these features first using &lt;span class="caps"&gt;CSS&lt;/span&gt;, then &lt;span class="caps"&gt;SASS&lt;/span&gt;. With &lt;span class="caps"&gt;CSS&lt;/span&gt;:&lt;/p&gt;
&lt;pre name='code' class='css'&gt;#menu {
  margin: 0;
  list-style: none;
}

#menu li {
  float: left;
}

#menu li a {
  display: block;
  float: left;
  padding: 4px 8px;
  text-decoration: none;
  background: #2277aa;
  color: white;
}

#menu li a:hover {
  background: #116699;
}

/* Make sure the color doesn't change when the current option is hovered. */
#menu li.current a, #menu li.current a:hover {
  background: white;
  color: black;
}&lt;/pre&gt;
&lt;p&gt;This isn&amp;#8217;t too bad, but our selectors keep getting longer and longer. Let&amp;#8217;s look at the same thing in &lt;span class="caps"&gt;SASS&lt;/span&gt;.&lt;/p&gt;
&lt;pre name='code' class='css'&gt;#menu
  :margin 0
  :list-style none
  li
    :float left
    a
      :display block
      :float left
      :padding 4px 8px
      :text-decoration none
      :color white
      :background = !menu_bg
      &amp;amp;:hover
        :background = !menu_bg - #111111
    &amp;amp;.current
      a, a:hover
        :background white
        :color black&lt;/pre&gt;

&lt;p&gt;The ampersand (&lt;code&gt;&amp;amp;&lt;/code&gt;) in &lt;span class="caps"&gt;SASS&lt;/span&gt; is a shortcut to insert the entire parent selector at that point. By using &lt;code&gt;&amp;amp;.current&lt;/code&gt; I am saying &amp;#8220;the parent selector with a class of current.&amp;#8221; &lt;code&gt;&amp;amp;:hover&lt;/code&gt; means &amp;#8220;the parent selector when hovered.&amp;#8221; This makes it easy to write complex selectors in a compact, easy-to-read manner.&lt;/p&gt;
&lt;p&gt;Another great thing about &lt;span class="caps"&gt;SASS&lt;/span&gt; is it has built in &lt;span class="caps"&gt;CSS&lt;/span&gt; color math. Note where I declared &lt;code&gt;:background = !menu_bg - #111111&lt;/code&gt;. That is equivalent to subtracting 1 from each of the values of the constant&amp;#8217;s color, which in this case yields &lt;code&gt;#116699&lt;/code&gt;. This is great, because now I can change the color of the menu and the hover state will automatically change without me having to manually find it and recalculate it for a new color. Note that whenever you are using constants or performing calculations you need to add the equals sign to your declaration.&lt;/p&gt;
&lt;h3&gt;Getting organized with a master.sass&lt;/h3&gt;
&lt;p&gt;Another way you can use &lt;span class="caps"&gt;SASS&lt;/span&gt; is to organize all of your &lt;span class="caps"&gt;CSS&lt;/span&gt; into a single file without having to worry about it in your view. I have recently started using this approach for a number of reasons:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;It allows me to control stylesheet inclusion from within the stylesheets themselves, making the structure more readable.&lt;/li&gt;
	&lt;li&gt;I can define global colors that can then be used in &lt;strong&gt;any&lt;/strong&gt; of the child stylesheets.&lt;/li&gt;
	&lt;li&gt;It&amp;#8217;s really easy!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In a new project, I always create a &lt;code&gt;master.sass&lt;/code&gt; that will look something like this:&lt;/p&gt;
&lt;pre name='code' class='css'&gt;// Define app-specific colors first
!green = #191
!gray = #555

// Now define globally applicable, general styles

body
  :font-family Arial, sans-serif
  
a
  :color = !green
  :text-decoration none
  :font-weight bold

// Now import all of your other SASS files, they will be
// automatically included in the same generated CSS file
// at compile time.

@import menu.sass
@import content.sass
@import admin.sass
@import users.sass&lt;/pre&gt;
&lt;p&gt;Using this structure I have a modular, easily expandable collection of stylesheets with global color constants and basic styles. In addition, I can add this to my Rails application with the simplest of calls:&lt;/p&gt;
&lt;pre name='code' class='html'&gt;&amp;lt;%= stylesheet_link_tag 'master' %&amp;gt;&lt;/pre&gt;
&lt;h3&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;Hopefully this gives you a taste of the easy awesomeness that is possible with &lt;span class="caps"&gt;SASS&lt;/span&gt;. The greatest thing about the library is you don&amp;#8217;t lose touch with writing &lt;span class="caps"&gt;CSS&lt;/span&gt; because &lt;span class="caps"&gt;SASS&lt;/span&gt; &lt;strong&gt;is&lt;/strong&gt; &lt;span class="caps"&gt;CSS&lt;/span&gt;, just with a few extras and shortcuts to make power-styling easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; A commenter pointed out that I forgot the &lt;code&gt;@&lt;/code&gt; before my import statements in the master.sass example, this has been fixed.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=ayq5VO0D"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=x5NJEKYf"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=x5NJEKYf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=y8UbcDpj"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/asyH4mbEwJY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/04/sass-the-better-more-powerful-css.html</feedburner:origLink></entry>
 
 <entry>
   <title>Use MacFUSE to Make a Boxee Torrent Dropbox</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/VQDVtTO7Du8/use-macfuse-to-make-a-boxee-torrent-dropbox.html" />
   <updated>2009-02-02T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/02/use-macfuse-to-make-a-boxee-torrent-dropbox</id>
   <content type="html">
&lt;p&gt;I recently set up &lt;a target="_blank" href="http://howto.wired.com/wiki/Hack_Your_Apple_TV_With_Boxee"&gt;Boxee on my Apple TV&lt;/a&gt; and have started using it for all of my media needs. While it’s great at using RSS feeds for torrents, having to SSH in to my Apple TV every time I wanted to start some random video downloading was growing to be a bit of a pain. So I decided to utilize MacFUSE and sshfs to mount a torrent dropbox so that I could just save torrents directly to the dropbox without manually SCP-ing them over to the Apple TV.&lt;/p&gt;

&lt;p&gt;First you’ll need to &lt;a target="_blank" href="http://macfuse.googlecode.com/files/MacFUSE-2.0.3%2C2.dmg" title="Download MacFUSE 2.3"&gt;install MacFUSE&lt;/a&gt; version 2.0 or greater. Once the installation is complete, you will need to get &lt;code&gt;sshfs&lt;/code&gt; to actually mount the remote folder to your local box. The easiest way is just to grab it off of SVN by typing the following in the Terminal:&lt;/p&gt;

&lt;pre&gt;$ cd ~/Desktop
$ svn co http://macfuse.googlecode.com/svn/trunk/filesystems/sshfs/binary sshfs-binaries&lt;/pre&gt;

&lt;p&gt;Once you’ve done that, you should copy over the correct binary (either tiger or leopard) to your &lt;code&gt;$PATH&lt;/code&gt; somewhere, (I chose &lt;code&gt;/opt/local/bin&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;$ cp sshfs-binaries/sshfs-static-leopard /opt/local/bin/sshfs&lt;/pre&gt;

&lt;p&gt;Now you’re ready to actually do the mounting. You will need a point on the filesystem to put the mount, I chose &lt;code&gt;/mnt&lt;/code&gt;. We simply need to perform the actual mounting now. Enter this command (assuming that your Apple TV can be SSH-ed into via &lt;code&gt;appletv.local&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;$ mkdir -p /mnt/boxee-torrent-drop
$ sshfs frontrow@appletv.local:/Users/frontrow/Library/Application\ Support/BOXEE/UserData/Torrents /mnt/boxee-torrent-drop&lt;/pre&gt;

&lt;p&gt;When prompted for a password enter &lt;code&gt;frontrow&lt;/code&gt; (or whatever your SSH password for your Apple TV is) and it should execute without error. If you now browse in the Finder to &lt;code&gt;/mnt&lt;/code&gt; you should see a MacFUSE drive icon alias pointing to your Boxee torrents folder. You can drag this mount to your Finder sidebar and whenever you save a torrent just save it to that directory. Boxee will now automatically pick it up and start downloading it!&lt;/p&gt;

&lt;p&gt;For bonus points, you could take this and:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Run it as a LoginItem so that you’re always mounted.&lt;/li&gt;
  &lt;li&gt;Set up remote SSH access to your Apple TV so that you can start torrents from anywhere in the world (please change your SSH password first).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=oBLYkrPT"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=cRhsxUAG"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=cRhsxUAG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=ios82tx7"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/VQDVtTO7Du8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/02/use-macfuse-to-make-a-boxee-torrent-dropbox.html</feedburner:origLink></entry>
 
 <entry>
   <title>The Case For Web Applications</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/ygwJrkuWmqM/the-case-for-web-applications.html" />
   <updated>2009-02-02T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/02/02/the-case-for-web-applications</id>
   <content type="html">&lt;p&gt;Neil McAllister recently wrote a piece on InfoWorld entitled &lt;a href="http://weblog.infoworld.com/fatalexception/archives/2009/01/the_case_agains.html"&gt;The Case Against Web Apps&lt;/a&gt;. In it, he outlines &amp;#8220;Five reasons why Web-based development might not be the best choice for your enterprise.&amp;#8221; Obviously, as an employee of a web application services and products company, I disagree strongly with that opinion.&lt;/p&gt;
&lt;p&gt;Web applications are not a &amp;#8220;trend&amp;#8221; in enterprise software development. They represent a fundamental shift in how software is developed, implemented and used in today&amp;#8217;s technological climate. But to be specific, let&amp;#8217;s go point-by-point through the &amp;#8220;case against web apps.&amp;#8221;&lt;/p&gt;
&lt;h3&gt;&amp;#8220;It&amp;#8217;s client-server all over again&amp;#8221;&lt;/h3&gt;
&lt;p&gt;It certainly is. The difference is, we&amp;#8217;re not living in a mainframe, dumb-terminal world anymore. Server infrastructure is cheap and scalable, and as more enterprises push their IT infrastructure to the cloud (see another article from InfoWorld: &lt;a href="http://weblog.infoworld.com/whurley/archives/2009/02/cloud_computing_1.html"&gt;IT needs to get over its cloud denial, or management will get over IT&lt;/a&gt;) the need for on-site datacenters will shrink and, for many companies, eventually disappear.&lt;/p&gt;
&lt;p&gt;Web applications require no client deployment, no versioning, no installation and no machine-by-machine support. There&amp;#8217;s no massive rollout procedure for a new version and no back-breaking process if there&amp;#8217;s a small but important glitch in a major release.&lt;/p&gt;
&lt;h3&gt;&amp;#8220;Web UIs are a mess&amp;#8221;&lt;/h3&gt;
&lt;p&gt;When each project has specific and individual user experience needs, isn&amp;#8217;t it good to reinvent the wheel a little bit? Having a blank canvas means having the chance to build exactly what is right for this application, not shoehorning an application into pre-defined constraints.&lt;/p&gt;
&lt;p&gt;Bad web sites and bad desktop application interfaces are equally impenetrable to the average user. The success of the user experience lies not in the hands of the chosen deployment platform but in the hands of a developer with an eye for user experience. I don&amp;#8217;t think it&amp;#8217;s a stretch to posit that the majority of such developers work either on web applications or for Apple. When was the last time you saw a beautiful Visual Basic application interface?&lt;/p&gt;
&lt;h3&gt;&amp;#8220;Browser technologies are too limiting.&amp;#8221;&lt;/h3&gt;
&lt;p&gt;&amp;#8220;User interface code written in such languages as C++, Objective C, or Python can often be both more efficient and more maintainable than code written for the Web paradigm.&amp;#8221; This statement rings false to me; when was the last time you saw a graphic designer who could pop open his trusty Visual Studio 2008 and recompile a project to tweak the user interface? The fundamental advantage of &lt;span class="caps"&gt;HTML&lt;/span&gt;/&lt;span class="caps"&gt;CSS&lt;/span&gt;/Javascript based interface development is that is accessible to a wholly different set of people, people who understand how users think and want to behave but don&amp;#8217;t necessarily have the programming chops to implement the actual code.&lt;/p&gt;
&lt;p&gt;The proliferation of Flash, Quicktime, and Silverlight can pretty much all be explained by one fact: &lt;span class="caps"&gt;HTML&lt;/span&gt; doesn&amp;#8217;t support embedded video. Few web developers turn to Flash or other technologies for much outside of rich multimedia playing. You also can&amp;#8217;t consider such a tool a liability when it is available for more than 99% of all web users.&lt;/p&gt;
&lt;p&gt;This also brings up a fundamental flaw in &amp;#8220;the case against web apps&amp;#8221;: if this is an article talking about using web applications for enterprise business applications, how are any of the concerns about browser compatibility valid? Don&amp;#8217;t most enterprises have control over what browsers get used by their employees? The &lt;a href="http://news.cnet.com/8301-1023_3-10108852-93.html"&gt;refusal of Internet Explorer 6 to kick the bucket&lt;/a&gt; certainly seems to indicate that companies have a great deal of control over how employees access the internet.&lt;/p&gt;
&lt;h3&gt;&amp;#8220;The big vendors call the shots.&amp;#8221;&lt;/h3&gt;
&lt;p&gt;Is this untrue of any development platform short of Linux? Companies are at the whim of Microsoft when they released an in-many-cases incompatible, largely disparaged upgrade to their operating system with Vista. That&amp;#8217;s much more of a moving target than the web standards, which with the exception of Internet Explorer (another Microsoft project) make writing cross-browser, cross-operating system applications a relative ease.&lt;/p&gt;
&lt;h3&gt;&amp;#8220;Should every employee have a browser?&amp;#8221;&lt;/h3&gt;
&lt;p&gt;You know what? Lots of people e-mail jokes to their families from their work accounts, let&amp;#8217;s not allow people to write e-mails anymore. I heard that sometimes people make personal calls from the office, so let&amp;#8217;s get rid of the phones, too. Not only is this point inherently distrustful of the work ethic and general competency of most employees, it doesn&amp;#8217;t even hold water: browsers can be used to access internal applications even if all outside internet access is restricted.&lt;/p&gt;
&lt;p&gt;In the end, I may have spent too much time here refuting his arguments without making the real case &lt;strong&gt;for web applications&lt;/strong&gt;. So, very briefly, here&amp;#8217;s it is:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Massively Agile:&lt;/strong&gt; Web applications can be built, deployed, and put into general use in a matter of weeks, not months or years. New features can be rolled out on a continuous basis rather than waiting a year for a new &amp;#8220;point release.&amp;#8221;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Massively Accessible:&lt;/strong&gt; Web applications can be accessed from any device that can access the internet, regardless of operating system or system requirements. As mobile phones become more web capable this becomes even more apparent and necessary. Desktop applications require completely separate development efforts.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;The Local Data Problem:&lt;/strong&gt; There&amp;#8217;s no need for &amp;#8220;shared&amp;#8221; folders and collision control on documents in a web application. Everything is on the server, everything is up-to-date as soon as it is accessed.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Web is the new Desktop:&lt;/strong&gt; Technologies such as &lt;a href="http://blogs.adobe.com/air/2009/01/air_passes_100_million_install.html"&gt;Adobe &lt;span class="caps"&gt;AIR&lt;/span&gt;&lt;/a&gt; and site-specific browsers have made it so that web applications are becoming more and more like desktop applications, bringing the ease of development and deployment with them.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Collaboration is King:&lt;/strong&gt; Web applications, due to their centralized nature, can naturally encourage less isolated, more collaborative work between employees.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Web applications aren&amp;#8217;t the solution to every problem a business faces. If you need graphically intense 3D visualizations for your buciness, web applications probably aren&amp;#8217;t the way to go for you. But for most businesses, most of the time, web applications will be more cost-effective, more useful and more agile than the alternative.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=zhsmBzxl"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=uVdt1GWn"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=uVdt1GWn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Q8O5lsv6"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/ygwJrkuWmqM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/02/02/the-case-for-web-applications.html</feedburner:origLink></entry>
 
 <entry>
   <title>HasAvatar: Defining an Application Vocabulary</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/rxD5QL4-QWM/has-avatar-defining-an-application-vocabulary.html" />
   <updated>2009-01-28T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/01/28/has-avatar-defining-an-application-vocabulary</id>
   <content type="html">&lt;p&gt;One of my favorite techniques to &lt;span class="caps"&gt;DRY&lt;/span&gt; up a Rails application is to pull out common functionality into a simple &amp;#8220;vocabularized method,&amp;#8221; by which I mean a simple descriptive method call that can be made from within your model or controller definition. For instance, in some applications I might have multiple models that have an &amp;#8220;avatar.&amp;#8221;&lt;/p&gt;
&lt;p&gt;These avatars all behave the same and should do the same things so I don&amp;#8217;t want to just repeat myself in the code. Instead I set up a file called &lt;code&gt;has_avatar.rb&lt;/code&gt; inside my &lt;code&gt;config/initializers&lt;/code&gt; folder. We use &lt;a href="http://thoughtbot.com/projects/paperclip"&gt;Paperclip&lt;/a&gt; for attachment handling at the moment, so I am going to create a wrapper for the specific Paperclip functionality I need for the avatars. Here&amp;#8217;s the code:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;module HasAvatar
  STYLES = { :large  =&amp;gt; ["200x200#", :png],
             :medium =&amp;gt; ["100x100#", :png], 
             :small  =&amp;gt; ["70x70#", :png],
             :little =&amp;gt; ["50x50#", :png],
             :tiny   =&amp;gt; ["24x24#", :png] }
             
  def self.included(base)
    base.extend ClassMethods
  end
  
  module ClassMethods
    def has_avatar
      has_attached_file :avatar,
                        PAPERCLIP_DEFAULTS.merge(
                          :styles =&amp;gt; HasAvatar::STYLES,
                          :default_style =&amp;gt; :medium,
                          :default_url =&amp;gt; "https://assets.presentlyapp.com/images/avatars/missing_:style.png",
                          :path =&amp;gt; ":account/avatars/:class/:login/:style.:extension"
                        )
    end
  end
end

ActiveRecord::Base.send :include, HasAvatar&lt;/pre&gt;
&lt;p&gt;We define a module, &lt;code&gt;HasAvatar&lt;/code&gt; that will add a new class method called &lt;code&gt;has_avatar&lt;/code&gt; into whatever class it is included. I defined a constant &lt;code&gt;STYLES&lt;/code&gt; that lets me access the style hash outside of the attachment definition. A final piece of DRYness in the code is the &lt;code&gt;PAPERCLIP_DEFAULTS&lt;/code&gt; constant which is just the default setup for all attachments (S3 Bucket, etc.) and I override the options I need for the avatars by &lt;code&gt;merge&lt;/code&gt;-ing them in.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  has_avatar
end

class Group &amp;lt; ActiveRecord::Base
  has_avatar
end&lt;/pre&gt;
&lt;p&gt;Now both users and groups will have all of the expected Paperclip functionality without having to repeat ourselves. This is a simple example but it shows the general practices behind building your &lt;strong&gt;application vocabulary&lt;/strong&gt;, which is just my made-up term for the abstract reusable components that are specific only to this application. Of course, if it&amp;#8217;s useful outside of the application, you might want to just go ahead and pluginize it!&lt;/p&gt;
&lt;p&gt;The usefulness of these abstracted methods also comes in through the inherently polymorphic nature of Ruby. Throughout my code I can write helpers, views and more to support avatars without caring whether the object in question is a &lt;code&gt;User&lt;/code&gt; or a &lt;code&gt;Group&lt;/code&gt;. Basically, the DRYer you start the DRYer you stay.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Xq1zSEpT"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=YRi1yF6i"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=YRi1yF6i" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=cvWhLO2G"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/rxD5QL4-QWM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/01/28/has-avatar-defining-an-application-vocabulary.html</feedburner:origLink></entry>
 
 <entry>
   <title>Twitter Search Plus: Find Replies Inline With Twitter Search</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/mvyKvKipLdY/twitter-search-plus-find-replies-inline-with-twitter-search.html" />
   <updated>2009-01-22T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2009/01/22/twitter-search-plus-find-replies-inline-with-twitter-search</id>
   <content type="html">&lt;p&gt;Last night after watching the &lt;a href="http://abc.go.com/primetime/lost/"&gt;Lost&lt;/a&gt; premiere I had a question to which I was having a hard time finding the answer. The show had just ended and I wanted to know (tiny spoiler alert) who the woman Benjamin Linus was talking to at the end of the episode was. Google was no help (the episode had finished mere minutes before) so I turned to Twitter for some real-time searching.&lt;/p&gt;
&lt;p&gt;By searching for &lt;a href="http://search.twitter.com/search?q=lost+old+woman"&gt;lost old woman&lt;/a&gt; I was able to find plenty of other people asking the same &lt;strong&gt;question&lt;/strong&gt; I had, but no one was giving the answer. I suspected that a reply to one of the tweets in question would have the answer so a few more minutes of manually searching for replies to the search result tweets finally yielded my answer. It also showed me how useful Twitter Search could be with a built-in way to find replies to the tweets. Rather than request the feature and wait until Twitter decides to implement it, I got my hands dirty with &lt;a href="http://www.greasespot.net/"&gt;Greasemonkey&lt;/a&gt; and rolled my own.&lt;/p&gt;
&lt;h3&gt;Twitter Search Plus&lt;/h3&gt;
&lt;p&gt;This userscript (which requires the &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/748"&gt;Greasemonkey Firefox Extension&lt;/a&gt; or equivalent userscript support in another browser) will automatically add a &amp;#8220;Find Replies&amp;#8221; link to the actions on Twitter search results and go out, find, and insert the replies to the user in question inline, just like the Show Conversation view. Here&amp;#8217;s a screenshot of it in action:&lt;/p&gt;
&lt;p align='center'&gt;&lt;img src="http://img.skitch.com/20090122-rttyy3yd9i141m22j41frnqmn1.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This makes it really convenient to discover if a tweet you found while searching sparked any conversation. While I used it for entertainment, you could easily also find out who replied to a negative post about your brand, or if anyone else has already answered a question you were about to answer.&lt;/p&gt;
&lt;h3&gt;Installation and Limitations&lt;/h3&gt;
&lt;p&gt;You can &lt;a href="http://gist.github.com/raw/50619/5b1607fd72e01d0e82e1f142c94666c8b8f82d4a/twitter_search_plus.user.js"&gt;install the script by following this link&lt;/a&gt; and see the source &lt;a href="http://gist.github.com/50619"&gt;right here&lt;/a&gt; as a GitHub Gist. The script has also been &lt;a href="http://userscripts.org/scripts/show/40970"&gt;posted to UserScripts.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Because there is no way to sort Twitter searches from oldest to newest, you will only see the 15 most recent replies to the user posted after the tweet in question. If the tweet is old or the user is extremely popular you might not get the replies you&amp;#8217;re looking for. I&amp;#8217;m open to suggestions as to how to make this work better.&lt;/p&gt;
&lt;p&gt;Happy Twittering!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=PgGO6lfc"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=EOMUKr9f"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=EOMUKr9f" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=qfpvy2x9"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/mvyKvKipLdY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2009/01/22/twitter-search-plus-find-replies-inline-with-twitter-search.html</feedburner:origLink></entry>
 
 <entry>
   <title>Sort Your Files By Date</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/0exSv3AXU2A/sort-your-files-by-date.html" />
   <updated>2008-12-04T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2008/12/04/sort-your-files-by-date</id>
   <content type="html">&lt;p&gt;Others have talked about people being &lt;strong&gt;&amp;#8220;searchers&amp;#8221;&lt;/strong&gt; or &lt;strong&gt;&amp;#8220;filers&amp;#8221;&lt;/strong&gt; when it comes to e-mail. I think the same thing applies to hard drive organization, and I&amp;#8217;m definitely a searcher. I don&amp;#8217;t have much in the way of organization in my folders short of basic overarching functional categories (Documents, Pictures, Rails, etc). Right now my Documents folder has 365 items in it and absolutely no canonical organization strategy. However, it rarely takes me more than a few seconds to find what I&amp;#8217;m looking for at any given point. The secret? I just sort my files by date.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="http://img.skitch.com/20081204-b989tgnyg2r6153w9h7u4gysd2.png" alt="" /&gt;&lt;/p&gt;
&lt;p style="text-align: left;"&gt;I may be giving myself too much credit here (this may be completely obvious to lots of people), but most of the people I have talked to about it never even thought about the idea of defaulting to a file sort other than by name. So why does sorting by date help?&lt;/p&gt;
&lt;p style="text-align: left;"&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Most of the time, I&amp;#8217;m looking for a file that I&amp;#8217;ve worked with recently.&lt;/li&gt;
	&lt;li&gt;A good 50% of the time, I&amp;#8217;m looking for the &lt;strong&gt;most recently modified file &lt;/strong&gt;(uploading docs to e-mails, finding the app I just downloaded etc).&lt;/li&gt;
	&lt;li&gt;I&amp;#8217;m a pretty good visual scanner, so I can usually spot what I&amp;#8217;m looking for without much trouble in a list of files.&lt;/li&gt;
	&lt;li&gt;If all else fails, it&amp;#8217;s not like I can&amp;#8217;t go back to sorting by name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So this isn&amp;#8217;t exactly the life-altering stuff of epiphanies, but it&amp;#8217;s a little time saver that helps me be more productive throughout the day.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=XibErPp3"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=oPFGM7eY"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=oPFGM7eY" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=xfrXwnib"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/0exSv3AXU2A" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/12/04/sort-your-files-by-date.html</feedburner:origLink></entry>
 
 <entry>
   <title>The Importance of External Downtime Resources</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/IIhtgbFyV40/the-importance-of-external-downtime-resources.html" />
   <updated>2008-11-28T00:00:00-08:00</updated>
   <id>http://mbleigh.com/2008/11/28/the-importance-of-external-downtime-resources</id>
   <content type="html">&lt;p&gt;Back in the days when &lt;a href="http://www.twitter.com"&gt;Twitter&lt;/a&gt; was going down early and often, the biggest complaint by users often wasn&amp;#8217;t that Twitter was down but rather that they didn&amp;#8217;t know what was happening or when it would be fixed. Thus the &lt;a href="http://status.twitter.com"&gt;Twitter Status Blog&lt;/a&gt; was born, an externally hosted Tumblr that would be updated when they were having issues. &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; did similarly after a recent bout of outages.&lt;/p&gt;
&lt;p&gt;Why are such resources so important? Because ultimately it&amp;#8217;s not the fact that a service you want to use is unavailable that&amp;#8217;s a problem so much as the &lt;strong&gt;feeling of helplessness&lt;/strong&gt; of something you want/need to use being unavailable with no hint as to why or when it will be back.&lt;/p&gt;
&lt;p&gt;Case in point: today is Black Friday and Live.com is offering a 12 hour 40% cash back promotion with HP. I&amp;#8217;ve been trying to get through for the past six hours with no success (the entire Live.com cashback section has been down for most of that time). This would be fine if I had any idea what the problem was, how I could ensure that I can get the cashback even with the site being down, or even a &amp;#8220;sorry, you&amp;#8217;re out of luck.&amp;#8221; A call to Microsoft support simply directed me to an e-mail support form with no promise of resolution before the deal expires. Instead I&amp;#8217;m a slave to my refresh button trying to get the deal during brief bouts of uptime.&lt;/p&gt;
&lt;p&gt;So if you have a product that people depend on, make sure you have some ways to let people know what&amp;#8217;s happening without depending on your app itself. &lt;a href="http://present.ly/"&gt;Present.ly&lt;/a&gt;, for instance, employs both a Twitter account that we monitor to quickly respond to any questions about service interruptions and a support site that is externally hosted and will continue to work even if Present.ly is down. It is only in the case of three independent services going down simultaneously that we will be out of luck.&lt;/p&gt;
&lt;p&gt;Ultimately all that matters is that your customers are happy. You can keep them happy even in times of outage by making sure that they know that you&amp;#8217;re working on it, you know about it and you care about it.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=3clVdHLn"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Y4YZ2OZH"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=Y4YZ2OZH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=uoOW0kWD"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/IIhtgbFyV40" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/11/28/the-importance-of-external-downtime-resources.html</feedburner:origLink></entry>
 
 <entry>
   <title>Hacking the Mid-End (Great Lakes Ruby Bash Edition)</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/MKDule1VC4k/hacking-the-mid-end-great-lakes-ruby-bash-edition.html" />
   <updated>2008-10-11T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/10/11/hacking-the-mid-end-great-lakes-ruby-bash-edition</id>
   <content type="html">&lt;p&gt;I just finished giving my &amp;#8220;Hacking the Mid-End&amp;#8221; talk at the Great Lakes Ruby Bash. It was a bit longer format, so I updated the slides a bit and added a third example to the code. The slides are embedded below and the new code is available in &lt;a href="http://github.com/intridea/talk-midend"&gt;the GitHub Repository&lt;/a&gt;.&lt;/p&gt;
&lt;div style="width:425px;margin:0 auto 15px;" id="__ss_651205"&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=midendslides-1223737810319305-8&amp;stripped_title=hacking-the-midend-great-lakes-ruby-bash-edition-presentation" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=midendslides-1223737810319305-8&amp;stripped_title=hacking-the-midend-great-lakes-ruby-bash-edition-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;p&gt;I&amp;#8217;m still at the conference, but I wanted to post up the slides and code immediately! Enjoy.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=dP0nKykR"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=3LYBhhgj"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=3LYBhhgj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=oymM6yZL"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/MKDule1VC4k" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/10/11/hacking-the-mid-end-great-lakes-ruby-bash-edition.html</feedburner:origLink></entry>
 
 <entry>
   <title>Colorist: Color Manipulation for Web Heads</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/1ye9Y1wF0ng/colorist-color-manipulation-for-webheads.html" />
   <updated>2008-08-18T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/08/18/colorist-color-manipulation-for-webheads</id>
   <content type="html">&lt;p&gt;While writing color customization code for a recent project, I once again ran into the fact that the existing color gems for Ruby seem to be built for vastly different purposes. To that end, I decided to write a new library for dead-simple manipulation of colors with an emphasis on ease-of-use and being useful for web developers.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;gem install colorist&lt;/pre&gt;
&lt;h3&gt;The Basics&lt;/h3&gt;
&lt;p&gt;To instantiate a color in &lt;strong&gt;Colorist&lt;/strong&gt;, you use a number of methods:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;require 'colorist'
include Colorist

red = Color.new(0xff0000)
red = 0xff0000.to_color
red = "red".to_color
red = "#f00".to_color
red = Color.from_rgb(255,0,0)&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I &lt;code&gt;include&lt;/code&gt; Colorist in these examples, but there&amp;#8217;s no reason you can&amp;#8217;t leave it namespaced i.e. &lt;code&gt;Colorist::Color&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;The idea is to give maximum flexibility without making it complicated. Once you&amp;#8217;ve instantiated a color, you can figure out a few tidbits about it and perform some basic operations:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;red.brightness # =&amp;gt; 0.299
red.r # =&amp;gt; 255
red.invert # =&amp;gt; #&amp;lt;Color #00ffff&amp;gt;
red.text_color # =&amp;gt; #&amp;lt;Color #ffffff&amp;gt;
red.to_s # =&amp;gt; "#ff0000"
red.to_s(:rgb) # =&amp;gt; "1.000, 0.000, 0.000"&lt;/pre&gt;
&lt;h3&gt;Operations&lt;/h3&gt;
&lt;p&gt;The real value of Colorist comes in comparison and addition. You can use normal operators with the colors to add them together, subtract them, and compare them based on brightness. You can also do this with the string or numeric representations of colors:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;red = 0xff0000.to_color
green = 0x00ff00.to_color
yellow = red + green
yellow = "red".to_color + "green"
yellow.to_s # =&amp;gt; "#ffff00"
red - 0.2 # =&amp;gt; #&amp;lt;Color #cc0000&amp;gt;&lt;/pre&gt;
&lt;p&gt;Comparisons work off of the brightness of a given color. You can also calculate the contrast between two colors using the W3C&amp;#8217;s formula:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;red = "red".to_color
red &amp;gt; "black".to_color # =&amp;gt; true
red &amp;gt; "white".to_color # =&amp;gt; false
red.contrast_with("green".to_color) # =&amp;gt; 0.500653594771242&lt;/pre&gt;
&lt;h3&gt;Get Coloring!&lt;/h3&gt;
&lt;p&gt;That&amp;#8217;s most of the basic functionality, for all of the details you can &lt;a href="http://colorist.rubyforge.org/"&gt;view the RDoc on RubyForge&lt;/a&gt;. The &lt;a href="http://github.com/mbleigh/colorist"&gt;source is available on GitHub&lt;/a&gt; and there is a &lt;a href="http://mbleigh.lighthouseapp.com/projects/15686-colorist"&gt;Lighthouse project&lt;/a&gt; for any bugs or feature requests. Enjoy!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=eQbQjxMv"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=U9bO2vLo"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=U9bO2vLo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=SkQTkBOW"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/1ye9Y1wF0ng" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/08/18/colorist-color-manipulation-for-webheads.html</feedburner:origLink></entry>
 
 <entry>
   <title>Fetches: Bringing Your ActionController Its Slippers</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/NTpukP7YsJI/fetches-bringing-your-actioncontroller-its-slippers.html" />
   <updated>2008-07-28T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/07/28/fetches-bringing-your-actioncontroller-its-slippers</id>
   <content type="html">&lt;p&gt;There is a piece of code that shows up more than 80% of the controllers that I write, and it goes a little something like this:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class UsersController &amp;lt; ApplicationController
  def user
    @user ||= User.find(params[:id])
  end
  helper_method :user
end&lt;/pre&gt;
&lt;p&gt;A simple memoization method to allow me to easily grab the parameter-referred user in all of my actions. If I&amp;#8217;m using nested routes, that means I can write two, maybe three of these methods into a controller. I&amp;#8217;m basically using slight variations on the same code 20 different times in an application. Since we live in a world that loves to be &lt;span class="caps"&gt;DRY&lt;/span&gt;, I thought, &amp;#8220;I can do better.&amp;#8221;&lt;/p&gt;
&lt;h3&gt;Fetches: Memoizing Your Parameter Record Retrieval&lt;/h3&gt;
&lt;p&gt;Fetches is a simple extension to ActionController that lets you simply define those kinds of fetch methods on a one-line command. For the example above, I can rewrite it like so:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class UsersController &amp;lt; ApplicationController
  fetches :user
end&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s pretty useful! Not only can I call the &amp;#8220;&lt;code&gt;user&lt;/code&gt;&amp;#8221; method from the controller, but it&amp;#8217;s automatically helperized so that I can use the same call in my views. Of course, there are times when more advanced fetching is called for, say using a method other than &lt;code&gt;find&lt;/code&gt; or storing to a different variable name. Let&amp;#8217;s take a look at a slightly more complex example:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;# assuming a route like /users/:user_id/articles/:id
class ArticlesController &amp;lt; ApplicationController
  fetches :user, :as =&amp;gt; :author, :from =&amp;gt; :user_id, :using =&amp;gt; :find_by_login
  fetches :article
end&lt;/pre&gt;
&lt;p&gt;Now if I were to call &amp;#8220;&lt;code&gt;author&lt;/code&gt;&amp;#8221; in any of my controller actions, it would be equivalent to &lt;code&gt;User.find_by_login(params[:user_id])&lt;/code&gt;. Similarly, calling &amp;#8220;&lt;code&gt;article&lt;/code&gt;&amp;#8221; is equivalent to &lt;code&gt;Article.find(params[:id])&lt;/code&gt;. The &amp;#8220;from&amp;#8221; option can also take a Proc in case your fetching is not simply a parameter key:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class UsersController &amp;lt; ApplicationController
  fetches :user, :from =&amp;gt; Proc.new{ |c| c.params[:user_id] || c.params[:id] }
end&lt;/pre&gt;
&lt;p&gt;The main advantages to &lt;strong&gt;fetches&lt;/strong&gt; are brevity, clarity and DRYness. I&amp;#8217;ve found that this method covers every use case for parameter-based fetching that I&amp;#8217;ve needed, and as such provides a much simpler, more readable, and shorter way to fetch models for use in your controller and views.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Fetches is available as a gem as well as in traditional plugin format. To install&lt;br /&gt;
as a gem, add this to your environment.rb:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;config.gem 'mbleigh-fetches', :source =&amp;gt; 'http://gems.github.com', :lib =&amp;gt; "fetches"&lt;/pre&gt;

&lt;p&gt;To install it as a traditional plugin:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;script/plugin install git://github.com/mbleigh/fetches.git&lt;/pre&gt;
&lt;h3&gt;Resources&lt;/h3&gt;
&lt;p&gt;The source is &lt;a href="http://github.com/mbleigh/fetches"&gt;available on GitHub&lt;/a&gt;, the &lt;a href="http://actsascommunity.com/projects/fetches"&gt;Acts As Community project&lt;/a&gt; is there for general discussion, and &lt;a href="http://mbleigh.lighthouseapp.com/projects/14793-fetches/overview"&gt;the Lighthouse&lt;/a&gt; is there for bugs and feature suggestions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;:&lt;/strong&gt; A commenter requested that the plugin be able to handle creation of new records in addition to fetching existing records. I have added in the &lt;code&gt;:initialize&lt;/code&gt; option to do just this. Examples:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;fetches :user, :initialize =&amp;gt; true # initialize from params[:user]
fetches :user, :initialize =&amp;gt; :author # initialize from params[:author]
fetches :user, :initialize =&amp;gt; Proc.new{ |c| {:login =&amp;gt; c.params[:login], :email =&amp;gt; c.params[:email]} }&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=ZjoY6jIX"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=W1lUdo3k"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=W1lUdo3k" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=DEc9aV2q"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/NTpukP7YsJI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/07/28/fetches-bringing-your-actioncontroller-its-slippers.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using HTTP Status Codes for Rails AJAX Error Handling</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/I5aMlxF4mac/using-http-status-codes-for-rails-ajax-error-handling.html" />
   <updated>2008-07-23T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/07/23/using-http-status-codes-for-rails-ajax-error-handling</id>
   <content type="html">&lt;p&gt;A problem that often arises in &lt;span class="caps"&gt;AJAX&lt;/span&gt;-based web applications is how to handle it when things go wrong. The user should be informed of the problem in a descriptive manner, but obviously the internal workings of the application should not be revealed. A generic and useful way to handle this problem is to use &lt;span class="caps"&gt;HTTP&lt;/span&gt; Status Codes to indicate the type of failure, and use the javascript to cope appropriately.&lt;/p&gt;
&lt;p&gt;In this example I will be using jQuery, but the principles behind are just as applicable to Prototype or any other Javascript library.&lt;/p&gt;
&lt;h3&gt;Your Friends 403 and 500&lt;/h3&gt;
&lt;p&gt;Anyone who&amp;#8217;s built a Rails site is familiar with the 500 error. That&amp;#8217;s the generic exception code thrown whenever something goes wrong in your application. Users should, hopefully, never ever see this when they&amp;#8217;re using the site. However, oftentimes there are exceptions or errors that users should experience just as result of improperly filling out fields, permissioning, etc. So how do we differentiate?&lt;/p&gt;
&lt;p&gt;The Rails &lt;code&gt;render&lt;/code&gt; method has the ability to render out an arbitrary &lt;span class="caps"&gt;HTTP&lt;/span&gt; Status Code (i.e. 500 for error, 404 for not found, and &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"&gt;many more&lt;/a&gt;). The &amp;#8220;403 Forbidden&amp;#8221; code means that the server understood the request made of it, but is refusing to complete it. This sounds like an apt description for typically &amp;#8220;caught&amp;#8221; exceptions. So let&amp;#8217;s use the 403 code to intelligently handle the exceptions that we &lt;strong&gt;want&lt;/strong&gt; to be seen by the user.&lt;/p&gt;
&lt;h3&gt;In the controller&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s take the simplest example, an invalid record. If you are creating a record via &lt;span class="caps"&gt;AJAX&lt;/span&gt;, a &lt;code&gt;flash[:error]&lt;/code&gt; with a &lt;code&gt;render :action =&amp;gt; "new"&lt;/code&gt; is not going to suffice. Let&amp;#8217;s try something like this instead:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class ItemsController &amp;lt; ApplicationController
  def create
    Item.create!(params[:item])
    # continue on your merry way if it works
  rescue ActiveRecord::RecordInvalid =&amp;gt; e
    respond_to do |format|
      format.html { 
        flash.now[:error] = "There was a problem creating the item."
        render :action =&amp;gt; "new"
      }
      # Render out the validation failed message with a
      # 403 status code.
      format.js { render :text =&amp;gt; e.message, :status =&amp;gt; 403 }
    end
  end
end&lt;/pre&gt;
&lt;p&gt;All right, now that we&amp;#8217;ve got it handled on the controller side, it&amp;#8217;s time to work some Javascript magic on our &lt;span class="caps"&gt;AJAX&lt;/span&gt; call.&lt;/p&gt;
&lt;pre name="code" class="javascript"&gt;
$('a#ajax_link').click(function() {
  $.ajax({
    url: '/items', 
    success:function(data, textStatus) {
      // do success things
    },
    error:function(request, textStatus, errorThrown) {
      // Use the specific message for a 403, but
      // a generic failure message for a 500
      var message = (request.status == 403) ? 
        request.responseText : "An unknown error occurred. Support has been contacted.";
      // Simple alert for example, but you can handle
      // however you want, such as populating an error message
      // div and making it appear.
      alert(message);
    }
    return false;
  });
});
&lt;/pre&gt;
&lt;p&gt;Now when your &lt;span class="caps"&gt;AJAX&lt;/span&gt; request fails, it will render a user-friendly error message if it&amp;#8217;s an &amp;#8216;expected&amp;#8217; error or a generic message if the request fails with an unexpected exception.&lt;/p&gt;
&lt;p&gt;This is a simple example, but by building a general framework for error expectations you can make it much easier to provide user-friendly error handling that gives them all of the information they need without revealing any of your internal processes.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Osju7P7S"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=vXUTqY5S"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=vXUTqY5S" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=mUbF2cZk"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/I5aMlxF4mac" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/07/23/using-http-status-codes-for-rails-ajax-error-handling.html</feedburner:origLink></entry>
 
 <entry>
   <title>UberKit Update: UberForms to Ease Form Building</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/KJB-C0QmPvs/uberkit-update-uberforms-to-ease-form-building.html" />
   <updated>2008-07-14T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/07/14/uberkit-update-uberforms-to-ease-form-building</id>
   <content type="html">&lt;p&gt;Last week the Uberkit kicked off with some helpers to make your menu-building much easier. This week we&amp;#8217;re following it up with &lt;b&gt;UberForms&lt;/b&gt;, a Form Builder that DRYs up your repetitive form stresses. Let&amp;#8217;s see how it works!&lt;/p&gt;
&lt;h3&gt;Building an Uber-er Form&lt;/h3&gt;
&lt;p&gt;UberForms automatically generate all of the standard boilerplate &lt;span class="caps"&gt;HTML&lt;/span&gt; that goes around your forms. By wrapping everything up in an easily style-able package, it becomes a much easier business to make new forms as well as re-use form styling across projects. With the form markup taken care of, you can focus on the more important aspects of your UI building and keep your views deadly clean.&lt;/p&gt;
&lt;p&gt;While UberForms are available as a standard form builder (&lt;code&gt;Uberkit::Forms::Builder&lt;/code&gt;), you may find it more useful in its helper form (automatically available when the UberKit plugin is loaded:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;% uberform_for :user do |f| %&amp;gt;
  &amp;lt;%= f.text_field :login %&amp;gt;
  &amp;lt;%= f.password_field :password %&amp;gt;
  &amp;lt;%= f.submit "Submit"%&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;
&lt;p&gt;This will automatically be translated into some nice, &lt;span class="caps"&gt;CSS&lt;/span&gt;-ready &lt;span class="caps"&gt;HTML&lt;/span&gt;:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;form method="post" class="uberform" action="/users"&amp;gt;
  &amp;lt;div class="field_row"&amp;gt;
    &amp;lt;label for="user_login"&amp;gt;Login:&amp;lt;/label&amp;gt;
    &amp;lt;input type="text" size="30" name="user[login]" id="user_login" class="text_field"/&amp;gt;
    &amp;lt;br/&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class="field_row"&amp;gt;
    &amp;lt;label for="user_password"&amp;gt;Password:&amp;lt;/label&amp;gt;
    &amp;lt;input type="password" size="30" name="user[password]" id="user_password" class="password_field"/&amp;gt;
    &amp;lt;br/&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;&lt;/pre&gt;
&lt;p&gt;You can also change the label, add a description or help text to a field by adding the relevant options:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;%= f.text_field :login, :label =&amp;gt; "Username", 
                         :help =&amp;gt; "Only a-z and underscores.", 
                         :description =&amp;gt; "The name you will use to log in." %&amp;gt;&lt;/pre&gt;
&lt;p&gt;Becomes&amp;#8230;&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;div class="field_row"&amp;gt;
  &amp;lt;label for="user_login"&amp;gt;Username:&amp;lt;/label&amp;gt;
  &amp;lt;input type="text" size="30" name="user[login]" label="Username" id="user_login" help="Only a-z and underscores." description="The name you will use to log in." class="text_field"/&amp;gt;
  &amp;lt;span class="help"&amp;gt;Only a-z and underscores.&amp;lt;/span&amp;gt;
  &amp;lt;span class="description"&amp;gt;The name you will use to log in.&amp;lt;/span&amp;gt;
  &amp;lt;br/&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p&gt;Finally, you can create custom &lt;span class="caps"&gt;HTML&lt;/span&gt; inside an UberForm field by passing a block:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;% f.custom :label =&amp;gt; "State", :for =&amp;gt; "user_state" do |f| %&amp;gt;
  &amp;lt;%= state_select :user, :state %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;
&lt;p&gt;Becomes&amp;#8230;&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;div class="field_row"&amp;gt;
  &amp;lt;label for="user_state"&amp;gt;State:&amp;lt;/label&amp;gt;
  &amp;lt;div class="pseudo_field"&amp;gt;
    &amp;lt;select id="user_state"&amp;gt;...&amp;lt;/select&amp;gt;
  &amp;lt;/div&amp;gt; 
  &amp;lt;br/&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p&gt;Easy, right? That&amp;#8217;s all there is to it, now you can be UberForming to your heart&amp;#8217;s content&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;To install the UberKit (which &lt;a href="http://www.intridea.com/tags/uberkit"&gt;includes more than just forms&lt;/a&gt;) you can do so either as a gem or a traditional plugin. As a gem, just add this to your environment.rb:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;config.gem 'mbleigh-uberkit', :lib =&amp;gt; 'uberkit', :source =&amp;gt; 'http://gems.github.com'&lt;/pre&gt;
&lt;p&gt;As a traditional Rails plugin:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;script/plugin install git://github.com/mbleigh/uberkit.git&lt;/pre&gt;
&lt;h3&gt;The Future of the UberKit&lt;/h3&gt;
&lt;p&gt;These two pieces are pretty helpful, but there&amp;#8217;s more coming for the UberKit. Stay tuned for more updates, including more hooks and ways to customize the UberKit to fit your needs as a developer.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=sQEjfKvw"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=AS5Eons3"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=AS5Eons3" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=hXUoECIt"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/KJB-C0QmPvs" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/07/14/uberkit-update-uberforms-to-ease-form-building.html</feedburner:origLink></entry>
 
 <entry>
   <title>UberKit: Building a Rails UI Swiss-Army Knife</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/Zj67C9GchCk/uberkit-building-a-rails-ui-swiss-army-knife.html" />
   <updated>2008-07-07T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/07/07/uberkit-building-a-rails-ui-swiss-army-knife</id>
   <content type="html">&lt;p&gt;So many of components we build into our web applications have a grain of an extractable element, a standardization waiting to happen. Starting today, I am putting together a &amp;#8220;Standard UI Kit&amp;#8221; for all of the tools that help me build interfaces faster. Together, they are called the &lt;strong&gt;UberKit&lt;/strong&gt;. This week, the first segment is coming: &lt;strong&gt;UberMenus&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;UberMenu: Abstract Menu Generation&lt;/h3&gt;
&lt;p&gt;Most people who build interfaces will build their menus with the same structure over and over. I finally took the time to abstract this out into a single helper that can pretty much serve all of my navigational needs. Here&amp;#8217;s how you use it in a view:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;% ubermenu do |m| %&amp;gt;
  &amp;lt;% m.action 'Home', '/' %&amp;gt;
  &amp;lt;% m.action 'Users', users_path %&amp;gt;
  &amp;lt;% m.action 'Log Out', logout_path, :class =&amp;gt; "special" %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;
&lt;p&gt;Becomes this &lt;span class="caps"&gt;HTML&lt;/span&gt; (assuming you&amp;#8217;re at the document root):&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li class="first current first_current"&amp;gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href="/users"&amp;gt;Users&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li class="special last"&amp;gt;&amp;lt;a href="/logout"&amp;gt;Log Out&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;current&lt;/code&gt; class will automatically be set on whichever page responds to the built-in Rails helper &lt;code&gt;current_page?&lt;/code&gt; and the &lt;code&gt;action&lt;/code&gt; syntax behaves just like a &lt;code&gt;link_to&lt;/code&gt;. If a given action has multiple classes, they will also be joined with underscores as an additional class for browsers that do not support multiple class declarations. But in addition to easily creating simple menus, you can also easily generate multi-level navigation menus:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;% ubermenu 'nav' do |m| %&amp;gt;
  &amp;lt;% m.action 'Home', home_path %&amp;gt;
  &amp;lt;% m.submenu 'Services', services_path do |s| %&amp;gt;
    &amp;lt;% s.action 'Service A', service_path('a') %&amp;gt;
    &amp;lt;% s.action 'Service B', service_path('b') %&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;
&lt;p&gt;Which will become this &lt;span class="caps"&gt;HTML&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul id='nav'&amp;gt;
  &amp;lt;li class='first current first_current'&amp;gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li class='last'&amp;gt;&amp;lt;a href="/services"&amp;gt;Services&amp;lt;/a&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;a href="/services/a"&amp;gt;Service A&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;a href="/services/b"&amp;gt;Service B&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;UberKit is available both as a gem and a traditional plugin. For the gem version, add this to your &lt;code&gt;environment.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;config.gem 'mbleigh-uberkit', :source =&amp;gt; "http://gems.github.com/", :lib =&amp;gt; "uberkit"&lt;/pre&gt;
&lt;p&gt;Or as a traditional plugin:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;script/plugin install git://github.com/mbleigh/uberkit.git&lt;/pre&gt;
&lt;h3&gt;Future of the UberKit&lt;/h3&gt;
&lt;p&gt;While &lt;strong&gt;UberMenu&lt;/strong&gt; is a useful tool, the &lt;strong&gt;UberKit&lt;/strong&gt; will continue to grow over time, so stay tuned for additions (next on the slate: &lt;strong&gt;UberForm&lt;/strong&gt;). It may also grow to include some common styles and javascripts that can be used in conjunction with the helpers to provide an even easier track to a full-fledged UI.&lt;/p&gt;
&lt;h3&gt;Resources&lt;/h3&gt;
&lt;p&gt;As always, the &lt;a href="http://github.com/mbleigh/uberkit"&gt;source is on GitHub&lt;/a&gt; and there is an &lt;a href="http://www.actsascommunity.com/projects/uberkit"&gt;Acts As Community Profile&lt;/a&gt; available as well. If you have any problems with it or would like to request new features, &lt;a href="http://mbleigh.lighthouseapp.com/projects/13921-uberkit/overview"&gt;enter them on the Lighthouse project&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=C7iPkbjE"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=lulBZ7CH"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=lulBZ7CH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=ClIUyMOF"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/Zj67C9GchCk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/07/07/uberkit-building-a-rails-ui-swiss-army-knife.html</feedburner:origLink></entry>
 
 <entry>
   <title>What the World Needs Now is CSS3</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/FovDpdS-yn8/what-the-world-needs-now-is-css3.html" />
   <updated>2008-07-02T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/07/02/what-the-world-needs-now-is-css3</id>
   <content type="html">&lt;p&gt;The discussion around &lt;span class="caps"&gt;HTML&lt;/span&gt; 5 has been heating up recently, with people advocating to get it finalized and implemented sooner rather than later (and lamenting the ulterior motives of major browser vendors in lobbying for specs). I simply can&amp;#8217;t get passionate about this fight, much as I&amp;#8217;ve tried. While some of the things that &lt;span class="caps"&gt;HTML&lt;/span&gt; 5 offers will certainly be a boon for web developers, by and large the issues that it addresses (in terms of interactivity) are surmountable simply by using the excellent Javascript libraries we&amp;#8217;ve all become dependent upon. The next version of the &lt;span class="caps"&gt;CSS&lt;/span&gt; specification, however, is an entirely different story.&lt;/p&gt;
&lt;p&gt;I recently started a new project and as an experiment decided to play with using the non-final &lt;code&gt;border-radius&lt;/code&gt; implementations available in Firefox and Safari. After using it for about 15 minutes, I decided that I would simply forgo rounded corners in the interface for Internet Explorer. After using it for three days, I am wondering why every designer and developer on the internet isn&amp;#8217;t simultaneously demanding immediate forced adoption of CSS3.&lt;/p&gt;
&lt;h3&gt;Styling is Fun Again&lt;/h3&gt;
&lt;p&gt;Our interfaces and style tastes have grown much more complex as the web has grown up, but the tools we use to implement those styles haven&amp;#8217;t been keeping up. It shouldn&amp;#8217;t feel like a trip to the dentist just to get a box to have some rounded edges. It shouldn&amp;#8217;t be a nightmare to try to use translucent pngs for overlays (admittedly this has nothing to do with CSS3 and everything to do with IE6, the browser that won&amp;#8217;t die no matter how much we pray).&lt;/p&gt;
&lt;p&gt;I can tell you that styling on the edge doesn&amp;#8217;t just feel good, it feels &lt;b&gt;amazing&lt;/b&gt;. I&amp;#8217;m able to implement in a few seconds what I might otherwise spend three hours styling while polluting my markup with hack tags.&lt;/p&gt;
&lt;h3&gt;Rounded Corners: Nemesis of Designers Everywhere&lt;/h3&gt;
&lt;p&gt;There is no good way to make rounded corners. The javascript libraries are buggy, images are limited in practicality, and getting it just right in all browsers is downright painful and usually ends up with markup something like this (and a whole mess of &lt;span class="caps"&gt;CSS&lt;/span&gt; to go with):&lt;/p&gt;
&lt;pre name='code' class='html'&gt;&amp;lt;div class='rounded'&amp;gt;
  &amp;lt;div class='tl'&amp;gt;
    &amp;lt;div class='tr'&amp;gt;
      &amp;lt;div class='bl'&amp;gt;
        &amp;lt;div class='br'&amp;gt;
          So much for semantics...
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p&gt;In the CSS3 specification, the same effect is achievable like so:&lt;/p&gt;
&lt;pre name='code' class='css'&gt;.rounded { border-radius: 10px; }&lt;/pre&gt;
&lt;p&gt;But it&amp;#8217;s not just a convenient way to shortcut the hacks to which we&amp;#8217;ve all grown accustomed, it opens up entirely new possibilities for design that would simply not be worth the effort to hack without it.&lt;/p&gt;
&lt;h3&gt;Lead By Example&lt;/h3&gt;
&lt;p&gt;Let me explain what I mean by example. Form design has always been one of the trickiest parts of web design, what can we do with a little &lt;span class="caps"&gt;CSS&lt;/span&gt; 3 magic? Let&amp;#8217;s say we have a simple form that takes a person&amp;#8217;s name:&lt;/p&gt;
&lt;pre name="code" class="html"&gt;&amp;lt;form id='sample_form'&amp;gt;
  &amp;lt;label for="name"&amp;gt;First Name:&amp;lt;/label&amp;gt;
  &amp;lt;input type='text' name="name" id="name"/&amp;gt;&amp;lt;br/&amp;gt;
  
  &amp;lt;label for="name"&amp;gt;Last Name:&amp;lt;/label&amp;gt;
  &amp;lt;input type='text' name="name" id="name"/&amp;gt;&amp;lt;br/&amp;gt;
  
  &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;&lt;/pre&gt;
&lt;p&gt;Simple enough, this turns out looking something like this:&lt;/p&gt;
&lt;div align="center"&gt;&lt;img src="http://intridea.com/assets/2008/7/2/form-unstyled.png" alt="" /&gt;&lt;/div&gt;
&lt;p&gt;Now we can add some standard &lt;span class="caps"&gt;CSS&lt;/span&gt; to make it look a little more acceptable:&lt;/p&gt;
&lt;pre name="code" class="css"&gt;label {
  display: block;
  float: left;
  width: 100px;
  font-weight: bold;
  padding: 4px 5px;
  font-family: Verdana, sans-serif;
  font-size: 12px;
  margin-bottom: 5px;
  clear: both;
  text-align: right;
}

input {
  font-size: 12px;
  margin-bottom: 5px;
}
button {
  margin-left: 115px;
  margin-top: 10px;
}&lt;/pre&gt;
&lt;p&gt;And our result is a perfectly usable form:&lt;/p&gt;
&lt;div align='center'&gt;&lt;img src="http://intridea.com/assets/2008/7/2/form-css2.png" alt="" /&gt;&lt;/div&gt;
&lt;p&gt;But what if we use just a taste of what CSS3 has to offer? We can make a form that looks completely unique without using a single image:&lt;/p&gt;
&lt;pre name="code" class="css"&gt;label {
  display: block;
  float: left;
  width: 100px;
  padding: 4px 5px;
  border: 2px solid #037;
  background: #06a;
  color: #fff;
  font-family: Verdana, sans-serif; 
  font-size: 12px;
  margin-bottom: 5px;
  font-weight: bold;
  clear: both;
  text-align: right;
  border-radius: 13px;
  border-top-right-radius: 0px;
  border-bottom-right-radius: 0px;
}

input {
  background: #fff;
  border: 2px solid #8ac;
  border-left: 0px;
  padding: 5px 5px;
  margin-top: 0;
  margin-bottom: 5px;
  margin-left: 0;
  border-radius: 5px;
  top-left-radius: 0px;
  border-bottom-left-radius: 0px;
}

button {
  background: #080;
  color: #fff;
  border: 2px solid #060;
  font-size: 12px;
  font-weight: bold;
  margin-left: 112px;
  padding: 5px 10px;
  border-radius: 13px;
}&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s a hefty chunk of code, but anyone experienced in writing &lt;span class="caps"&gt;CSS&lt;/span&gt; can knock something like that out in about five minutes. The result is well worth it:&lt;/p&gt;
&lt;div align='center'&gt;&lt;img src="http://intridea.com/assets/2008/7/2/form-css3.png" alt="" /&gt;&lt;/div&gt;
&lt;p&gt;This kind of styling opens up with the application of &lt;strong&gt;just a single new attribute&lt;/strong&gt; from the &lt;a href="http://www.w3.org/Style/CSS/current-work"&gt;CSS3 draft specifications&lt;/a&gt;. Designers have had to hack, cheat, and wrangle every semi-complex interface that has been developed in the last 5 years thanks to the limitations of &lt;span class="caps"&gt;CSS&lt;/span&gt; (and more specifically the limitations of Internet Explorer), but it doesn&amp;#8217;t have to stay that way forever.&lt;/p&gt;
&lt;h3&gt;State of the Browser&lt;/h3&gt;
&lt;p&gt;The complete CSS3 spec is not coming to a browser near you any time soon (more accurately not &lt;strong&gt;all&lt;/strong&gt; browsers), and that&amp;#8217;s a real shame. It brings to the table powerful new tools that can really enable the kind of semantic markup that we all wish was possible with today&amp;#8217;s browsers. Rounded corners are just the &amp;#8220;tip of the iceberg&amp;#8221;; once CSS3 sees widespread adoption, interface design will take a leap forward unlike any it has seen before.&lt;/p&gt;
&lt;p&gt;In the meantime, keep an eye out on the &lt;a href="http://nightly.webkit.org/"&gt;WebKit Nightlies&lt;/a&gt; for cutting edge &lt;span class="caps"&gt;CSS&lt;/span&gt; implementations (just added: &lt;a href="http://disruptive-innovations.com/zoo/cssvariables/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Variables&lt;/a&gt;). Five years from now we&amp;#8217;ll look at the troubles we used to have and laugh. Until then, a person can dream&amp;#8230;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=gF9pHN56"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=oaKYtxTf"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=oaKYtxTf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=dFxGFobk"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/FovDpdS-yn8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/07/02/what-the-world-needs-now-is-css3.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using RSpec and Autotest While Writing Rails Plugins</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/ofBdmPC4mMc/using-rspec-and-autotest-while-writing-rails-plugins.html" />
   <updated>2008-06-25T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/06/25/using-rspec-and-autotest-while-writing-rails-plugins</id>
   <content type="html">&lt;p&gt;&lt;a href="http://rspec.info"&gt;RSpec&lt;/a&gt; is a great tool that has come to replace &lt;code&gt;Test::Unit&lt;/code&gt; for many &lt;a href="http://www.rubyonrails.com/"&gt;Rails&lt;/a&gt; developers. &lt;a href="http://www.zenspider.com/ZSS/Products/ZenTest/"&gt;Autotest&lt;/a&gt; makes it go even faster, and has become an indispensable part of my development environment. However, it has always been somewhat-to-extremely difficult to use RSpec when developing Rails plugins. In this post I will walk through step-by-step how to get RSpec and Autotest working with your plugin.&lt;/p&gt;
&lt;p&gt;This plugin is assuming that you are running Rails &amp;gt;= 2.1 and have already installed RSpec and RSpec::Rails as plugins in your Rails project like so:&lt;/p&gt;
&lt;pre name='code' class='bash'&gt;script/plugin install git://github.com/dchelimsky/rspec.git
script/plugin install git://github.com/dchelimsky/rspec-rails.git&lt;/pre&gt;
&lt;p&gt;And also gotten RSpec up and running by calling &lt;code&gt;script/generate rspec&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Generate It&lt;/h3&gt;
&lt;p&gt;Luckily, I wasn&amp;#8217;t the first person who ever wanted to create a plugin that was tested with RSpec. &lt;a href="http://github.com/pat-maddox/rspec-plugin-generator/tree/master"&gt;The Rspec Plugin Generator&lt;/a&gt; will do most of the heavy lifting for us when we start out. Just install it like so:&lt;/p&gt;
&lt;pre name='code' class='bash'&gt;script/plugin install git://github.com/pat-maddox/rspec-plugin-generator.git&lt;/pre&gt;
&lt;p&gt;And you&amp;#8217;re ready to get started. I&amp;#8217;m assuming here that this is a brand new plugin, if it&amp;#8217;s already in development you may need to run this in a fresh directory and then copy/paste files as needed to glue it together. Let&amp;#8217;s say I&amp;#8217;m writing a plugin called &lt;code&gt;new_fu&lt;/code&gt;. I can generate an RSpec-ready plugin simply by calling:&lt;/p&gt;
&lt;pre name='code' class='bash'&gt;script/generate rspec_plugin new_fu&lt;/pre&gt;
&lt;p&gt;This will generate the standard plugin structure as well as some extra files:&lt;/p&gt;
&lt;pre name='code' class='bash'&gt;create  vendor/plugins/new_fu/spec
create  vendor/plugins/new_fu/spec/spec_helper.rb
create  vendor/plugins/new_fu/spec/new_fu_spec.rb&lt;/pre&gt;
&lt;p&gt;You can take a look at these to see how they work, but pretty simply they hook your plugin up so that it can be run with &lt;code&gt;rake spec:plugins&lt;/code&gt;. Let&amp;#8217;s add a simple example to our &lt;code&gt;new_fu_spec.rb&lt;/code&gt; file:&lt;/p&gt;
&lt;pre name='code' class='ruby'&gt;require File.dirname(__FILE__) + '/spec_helper'

describe "NewFu" do
  it "should have a pending spec"
end&lt;/pre&gt;
&lt;p&gt;Now if you run &lt;code&gt;rake spec:plugins&lt;/code&gt; you should see one pending spec. Congratulations, your plugin is now running on RSpec!&lt;/p&gt;
&lt;h3&gt;Autotest Like a Champ&lt;/h3&gt;
&lt;p&gt;Ok, so now we&amp;#8217;re up and running with RSpec on our plugin. That&amp;#8217;s great, but if you have several plugins in the same Rails app that all have specs, it starts to get messy when you run that &lt;code&gt;rake spec:plugins&lt;/code&gt;. Not to mention how long it takes between runs! We need to get an autotest setup like we have for our main Rails app!&lt;/p&gt;
&lt;p&gt;I struggled with getting this to work for a long time, so thanks to &lt;a href="http://rails.aizatto.com/2007/11/19/autotest-ing-your-rails-plugin/"&gt;this post on Rails Symphonies&lt;/a&gt; for finally pointing me in the right direction. First we need to create an &lt;code&gt;autotest/discover.rb&lt;/code&gt; file in our plugin&amp;#8217;s &lt;code&gt;lib&lt;/code&gt; directory. In that file, put this code:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;$:.push(File.join(File.dirname(__FILE__), %w[.. .. rspec]))  
   
Autotest.add_discovery do  
  "rspec" 
end&lt;/pre&gt;
&lt;p&gt;This gets us almost exactly where we want to be. However, the first time I ran it I had two problems: some specs that I had written were strangely failing, and it wasn&amp;#8217;t in color or following the rest of my &lt;code&gt;spec.opts&lt;/code&gt; preferences from my main app!&lt;/p&gt;
&lt;p&gt;To remedy this, we need a &lt;code&gt;spec.opts&lt;/code&gt; in the &lt;code&gt;spec&lt;/code&gt; directory of the plugin. You can either copy and paste it in from your Rails app (my recommendation if you are publishing your plugin) or you can just create a softlink back to it:&lt;/p&gt;
&lt;pre name='code' class='bash'&gt;ln -s ../../../../spec/spec.opts spec.opts&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s it! Now if you run &lt;code&gt;autotest&lt;/code&gt; you should be running all of the specs for your plugin just as you would if you were running them for your app. Note that this doesn&amp;#8217;t hook in to your app&amp;#8217;s &lt;code&gt;autotest&lt;/code&gt;, which may be desirable or undesirable to your specific needs.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Xz6EzLJu"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=e5oZzsZi"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=e5oZzsZi" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=uYyOQZLq"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/ofBdmPC4mMc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/06/25/using-rspec-and-autotest-while-writing-rails-plugins.html</feedburner:origLink></entry>
 
 <entry>
   <title>SubdomainFu: A New Way To Tame The Subdomain</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/hnmwiyGm8vI/subdomain-fu-a-new-way-to-tame-the-subdomain.html" />
   <updated>2008-06-23T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/06/23/subdomain-fu-a-new-way-to-tame-the-subdomain</id>
   <content type="html">&lt;p&gt;An extremely common practice for Rails applications is to provide keyed&lt;br /&gt;
access through subdomains (i.e. http://someaccount.awesomeapp.com/). However,&lt;br /&gt;
there has never been a real unified convention for handling this functionality.&lt;br /&gt;
&lt;a href="http://github.com/rails/account_location/tree/master"&gt;DHH&amp;#8217;s Account Location&lt;/a&gt;&lt;br /&gt;
works for some circumstances but is more tailored for a &lt;a href="http://www.basecamphq.com/"&gt;Basecamp&lt;/a&gt; domain model&lt;br /&gt;
(i.e. the app is on a separate domain from all other functionality, so you&lt;br /&gt;
can always expect a subdomain) than the more common usage of one domain only.&lt;/p&gt;
&lt;p&gt;SubdomainFu aims to provide a simple, generic toolset for dealing with subdomains&lt;br /&gt;
in Rails applications. Rather than tie the functionality to something specific&lt;br /&gt;
like an account, SubdomainFu simply provides a foundation upon which any&lt;br /&gt;
subdomain-keyed system can easily be built.&lt;/p&gt;
&lt;h3&gt;Usage Fu&lt;/h3&gt;
&lt;p&gt;SubdomainFu works by riding on top of the &lt;span class="caps"&gt;URL&lt;/span&gt; Rewriting engine provided with&lt;br /&gt;
Rails. This way you can use it anywhere you normally generate URLs: through&lt;br /&gt;
&lt;code&gt;url_for&lt;/code&gt;, in named routes, and in &lt;code&gt;resources&lt;/code&gt;-based routes. There&amp;#8217;s a small&lt;br /&gt;
amount of configuration that is needed to get you running (though the defaults&lt;br /&gt;
should work for most).&lt;/p&gt;
&lt;p&gt;To set it up, you can modify any of these settings (the defaults are shown):&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;# in environment.rb
  
# These are the sizes of the domain (i.e. 0 for localhost, 1 for something.com)
# for each of your environments
SubdomainFu.tld_sizes = { :development =&amp;gt; 0,
                          :test =&amp;gt; 0,
                          :production =&amp;gt; 1 }

# These are the subdomains that will be equivalent to no subdomain
SubdomainFu.mirrors = ["www"]

# This is the "preferred mirror" if you would rather show this subdomain
# in the URL than no subdomain at all.
SubdomainFu.preferred_mirror = "www"&lt;/pre&gt;
&lt;p&gt;Now when you&amp;#8217;re in your application, you will have access to two useful&lt;br /&gt;
features: a &lt;code&gt;current_subdomain&lt;/code&gt; method and the &lt;span class="caps"&gt;URL&lt;/span&gt; Rewriting helpers.&lt;br /&gt;
The &lt;code&gt;current_subdomain&lt;/code&gt; method will give you the current subdomain or&lt;br /&gt;
return nil if there is no subdomain or the current subdomain is a mirror:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;# http://some_subdomain.myapp.com/
current_subdomain # =&amp;gt; "some_subdomain"

# http://www.myapp.com/ or http://myapp.com/
current_subdomain # =&amp;gt; nil

# http://some.subdomain.myapp.com
current_subdomain # =&amp;gt; "some.subdomain"&lt;/pre&gt;
&lt;p&gt;The &lt;span class="caps"&gt;URL&lt;/span&gt; rewriting features of SubdomainFu come through a &lt;code&gt;:subdomain&lt;/code&gt; option&lt;br /&gt;
passed to any &lt;span class="caps"&gt;URL&lt;/span&gt; generating method. Here are some examples (in these examples,&lt;br /&gt;
the current page is considered to be &amp;#8216;http://intridea.com/&amp;#8217;):&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;url_for(:controller =&amp;gt; "my_controller", 
  :action =&amp;gt; "my_action", 
  :subdomain =&amp;gt; "awesome") # =&amp;gt; http://awesome.intridea.com/my_controller/my_action
  
users_url(:subdomain =&amp;gt; false)  # =&amp;gt; http://intridea.com/users

# The full URL will be generated if the subdomain is not the same as the
# current subdomain, regardless of whether _path or _url is used.
users_path(:subdomain =&amp;gt; "fun") # =&amp;gt; http://fun.intridea.com/users
users_path(:subdomain =&amp;gt; false) # =&amp;gt; /users&lt;/pre&gt;
&lt;p&gt;While this is just a simple set of tools, it can allow the easy creation&lt;br /&gt;
of powerful subdomain-using tools. Note that the easiest way to locally&lt;br /&gt;
test multiple subdomains on your app is to edit &lt;code&gt;/etc/hosts&lt;/code&gt; and add&lt;br /&gt;
subdomains like so:&lt;/p&gt;
&lt;pre name="code"&gt;127.0.0.1	localhost subdomain1.localhost subdomain2.localhost www.localhost&lt;/pre&gt;
&lt;p&gt;Adding an entry for each subdomain you want to use locally. Then you need&lt;br /&gt;
to flush your local &lt;span class="caps"&gt;DNS&lt;/span&gt; cache to make sure your changes are picked up:&lt;/p&gt;
&lt;pre&gt;sudo dscacheutil -flushcache&lt;/pre&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;SubdomainFu is available both as a traditional plugin and as a GemPlugin&lt;br /&gt;
for Rails 2.1 and later. For a traditional plugin, install like so:&lt;/p&gt;
&lt;pre&gt;script/plugin install git://github.com/mbleigh/subdomain-fu.git&lt;/pre&gt;
&lt;p&gt;For a GemPlugin, add this dependency to your &lt;code&gt;environment.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;config.gem 'mbleigh-subdomain-fu', :source =&amp;gt; "http://gems.github.com/", :lib =&amp;gt; "subdomain-fu"&lt;/pre&gt;
&lt;h3&gt;Implementing A Simple Account Key System&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s take this functionality and implement a simple account-key system based&lt;br /&gt;
off of the subdomain. We&amp;#8217;ll start with some controller code (assuming that&lt;br /&gt;
we have an Account model with a &amp;#8216;subdomain&amp;#8217; field):&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class ApplicationController &amp;lt; ActionController::Base
  protected
  
  # Will either fetch the current account or return nil if none is found
  def current_account
    @account ||= Account.find_by_subdomain(current_subdomain)
  end
  # Make this method visible to views as well
  helper_method :current_account
  
  # This is a before_filter we'll use in other controllers
  def account_required
    unless current_account
      flash[:error] = "Could not find the account '#{current_subdomain}'"
      redirect_to :controller =&amp;gt; "site", :action =&amp;gt; "home", :subdomain =&amp;gt; false
    end
  end
end&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s really all we need for a basic setup, now let&amp;#8217;s say we have a&lt;br /&gt;
&lt;code&gt;ProjectsController&lt;/code&gt; that you must specify an account to access:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class ProjectsController &amp;lt; ApplicationController
  # Redirect users away if no subdomain is specified
  before_filter :account_required
end&lt;/pre&gt;
&lt;p&gt;There&amp;#8217;s lots more you can do with the plugin, but this is a simple use case&lt;br /&gt;
that everyone can relate to.&lt;/p&gt;
&lt;h3&gt;Resources and Plans&lt;/h3&gt;
&lt;p&gt;A feature that I hoped would make it to the first release of SubdomainFu&lt;br /&gt;
but is now a planned feature is subdomain-aware routing so that you can&lt;br /&gt;
add conditional subdomain routes to your &lt;code&gt;routes.rb&lt;/code&gt; file. Keep an eye&lt;br /&gt;
out for more on that in the future.&lt;/p&gt;
&lt;p&gt;In the meantime, the project will live at its home on &lt;a href="http://www.actsascommunity.com/projects/subdomain-fu/"&gt;Acts As Community&lt;/a&gt; for intermittent&lt;br /&gt;
updates, &lt;a href="http://github.com/mbleigh/subdomain-fu/"&gt;is available on GitHub&lt;/a&gt; as always, and bugs/feature requests may&lt;br /&gt;
be passed on through the &lt;a href="http://mbleigh.lighthouseapp.com/projects/13148-subdomain-fu"&gt;Lighthouse&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=ejlnNlMS"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=8PUji4m7"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=8PUji4m7" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=LKyftwap"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/hnmwiyGm8vI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/06/23/subdomain-fu-a-new-way-to-tame-the-subdomain.html</feedburner:origLink></entry>
 
 <entry>
   <title>GemPlugins: A Brief Introduction to the Future of Rails Plugins</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/jCU4NCmzz0I/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins.html" />
   <updated>2008-06-11T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/06/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins</id>
   <content type="html">&lt;p&gt;The new &lt;a href="http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies"&gt;Gem Dependencies&lt;/a&gt; of Rails 2.1 give developers an easier-than-ever ability to keep track of and maintain the various library dependencies inherent with any project. However, a much-overlooked additional feature of the Gem Dependencies is the ability to package traditional Rails plugins as a gem and have them hooked in properly. This article is designed as an introduction to how to write and use plugins as gems in Rails projects.&lt;/p&gt;
&lt;h3&gt;The Basics&lt;/h3&gt;
&lt;p&gt;The basic method by which this is achievable is that any plugin included through a &lt;code&gt;config.gem&lt;/code&gt; command will automatically have the gem-packed file &lt;code&gt;rails/init.rb&lt;/code&gt; run upon Rails&amp;#8217;s initialization. All it takes is a little bit of effort, and any Rails plugin can be packaged as a gem and easily depended upon through gem dependencies.&lt;/p&gt;
&lt;p&gt;You may be wondering why this is a &amp;#8220;big deal.&amp;#8221; Plugins are already dead simple to install in Rails (and you can even &lt;code&gt;script/plugin install&lt;/code&gt; straight from Git now!), why do we need GemPlugins? It&amp;#8217;s simple, really: &lt;a href="http://www.rubygems.org/"&gt;RubyGems&lt;/a&gt; are a rock-solid established way of easily distributing &lt;strong&gt;versioned&lt;/strong&gt; reusable bits of code. Using gems for plugins allows for a greater standardization of the way in which plugins are maintained and distributed, as well as a simple path for version-locking to ensure compatibility with legacy code etc.&lt;/p&gt;
&lt;p&gt;Another reason that GemPlugins are important is that they provide a level of abstraction from Rails: by releasing a gem &lt;code&gt;rails/init.rb&lt;/code&gt; you could also use the same exact code to release a &lt;a href="http://www.merbivore.com/"&gt;Merb&lt;/a&gt; plugin or any other framework that supports gemified add-ons. I think you will begin to see a number of cross-framework plugins be developed as Rails gets some company and shares alike.&lt;/p&gt;
&lt;h3&gt;Using a GemPlugin&lt;/h3&gt;
&lt;p&gt;First, let&amp;#8217;s go through the process required to use an existing gem plugin. I&amp;#8217;m going to be using my &lt;a href="http://intridea.com/2008/6/9/acts-as-taggable-on-grows-up"&gt;Acts As Taggable On&lt;/a&gt; plugin as an example throughout because I just recently went through the process of making it available as a gem.&lt;/p&gt;
&lt;p&gt;First, you will need to include the dependency in your &lt;code&gt;environment.rb&lt;/code&gt; file. I&amp;#8217;m assuming here that most plugins are going to be hosted on &lt;a href="http://www.github.com/"&gt;GitHub&lt;/a&gt;, but the same should be true for any gem source.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;# in environment.rb
  
config.gem "mbleigh-acts-as-taggable-on", :source =&amp;gt; "http://gems.github.com", :lib =&amp;gt; "acts-as-taggable-on"&lt;/pre&gt;
&lt;p&gt;This is the standard usage of gem dependencies, and for more info on this you can &lt;a href="http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies"&gt;see Ryan Daigle&amp;#8217;s post&lt;/a&gt; or &lt;a href="http://railscasts.com/episodes/110"&gt;watch the RailsCast on the subject&lt;/a&gt;. Now assuming that you don&amp;#8217;t already have the gem in question installed, it&amp;#8217;s simple to grab it:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;rake gems:install&lt;/pre&gt;
&lt;p&gt;This will automatically install any gem dependencies in your project, and will tell you what&amp;#8217;s happening the same as if you had run &lt;code&gt;gem install&lt;/code&gt; from the command line.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it! Once you have successfully installed the necessary gem, you can simply start up your Rails server and the plugin will be loaded and initialized as though it were living in your &lt;code&gt;vendor/plugins&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Now that you know how to &lt;b&gt;use&lt;/b&gt; a GemPlugin, I&amp;#8217;ll show you how you can take an existing plugin and gemify it quickly and painlessly.&lt;/p&gt;
&lt;h3&gt;Making a GemPlugin&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s say I have a plugin called &lt;code&gt;awesome_fu&lt;/code&gt; that lives on GitHub at &lt;code&gt;mbleigh/awesome-fu&lt;/code&gt;. I&amp;#8217;ve already released this plugin, it works great, and now I want to make it compatible with GemPlugins.&lt;/p&gt;
&lt;p&gt;First, let&amp;#8217;s create a &lt;a href="http://www.rubygems.org/read/chapter/20"&gt;gemspec&lt;/a&gt; called &lt;code&gt;awesome-fu.gemspec&lt;/code&gt; in line with the requirements for the &lt;a href="http://gems.github.com"&gt;GitHub Gem Repository&lt;/a&gt;. In order to make the file list, I usually find it&amp;#8217;s easiest to &amp;#8220;&lt;code&gt;find **&lt;/code&gt;&amp;#8221; in the plugin directory, then copy it into &lt;a href="http://www.macromates.com/"&gt;TextMate&lt;/a&gt;, make the modifications I need for manifest (using a regular expression to quote each of the files), and saving it in the spec. If you have only a few files in your plugin, it may be easier just to add them by hand.&lt;/p&gt;
&lt;p&gt;Next we need to add &lt;code&gt;rails/init.rb&lt;/code&gt;. This is a little bit troublesome, because we still want our plugin to work if installed through the traditional method, so we also need &lt;code&gt;init.rb&lt;/code&gt; to run the same code (&lt;a href="http://rails.lighthouseapp.com/projects/8994/tickets/272-make-plugins-also-initialize-form-rails-init-rb#ticket-272-1"&gt;this is automatically fine in edge Rails&lt;/a&gt;). What I did for my plugin is copy all of my &lt;code&gt;init.rb&lt;/code&gt; code into &lt;code&gt;rails/init.rb&lt;/code&gt; and then change &lt;code&gt;init.rb&lt;/code&gt; to the following:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;require File.dirname(__FILE__) + "/rails/init"&lt;/pre&gt;
&lt;p&gt;Now they both run the same code without any kind of replication, great! This means that now I have set up my plugin to work equally as a GemPlugin or a traditional plugin with just a couple minutes of work.&lt;/p&gt;
&lt;p&gt;All that&amp;#8217;s left to do is switch on the RubyGem setting for my GitHub project, update the &lt;span class="caps"&gt;README&lt;/span&gt;, and push! Now anyone will be able to easily require the plugin as a gem dependency and you will get all of the accolades associated with releasing your plugin the &amp;#8220;new and hip&amp;#8221; way.&lt;/p&gt;
&lt;h3&gt;Caveat Coder&lt;/h3&gt;
&lt;p&gt;The one problem with GemPlugins that I have run into is that if you unpack your gems using &amp;#8220;&lt;code&gt;rake gems:unpack&lt;/code&gt;&amp;#8221; the &lt;code&gt;rails/init.rb&lt;/code&gt; file is not run on initialization. &lt;a href="http://rails.lighthouseapp.com/projects/8994/tickets/122-rails-init-rb-doesn-t-get-called-for-unpacked-gems"&gt;This is a known issue&lt;/a&gt; that is supposed (?) to be resolved but I have still experienced this problem in my experiments. Hopefully this issue will be fully resolved in edge Rails soon and the glorious future of GemPlugins can begin.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=j8iAKgw1"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=5qXLma4o"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=5qXLma4o" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=nK4nsUzk"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/jCU4NCmzz0I" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/06/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins.html</feedburner:origLink></entry>
 
 <entry>
   <title>ActsAsTaggableOn Grows Up</title>
   <link href="http://feedproxy.google.com/~r/mbleigh/~3/PjHalECH2cc/acts-as-taggable-on-grows-up.html" />
   <updated>2008-06-09T00:00:00-07:00</updated>
   <id>http://mbleigh.com/2008/06/09/acts-as-taggable-on-grows-up</id>
   <content type="html">&lt;p&gt;Acts As Taggable On (&lt;a href="http://intridea.com/2007/12/4/announcing-acts_as_taggable_on"&gt;original post here&lt;/a&gt;), the tagging plugin with custom tag contexts, has gathered up some great new features over the past weeks thanks to the efforts of the community as well as &lt;a href="http://www.intridea.com/people"&gt;fellow Intrideans Pradeep Elankumaran and Brendan Lim&lt;/a&gt;. I just wanted to take this opportunity to go over some of what&amp;#8217;s new and interesting in the world of &lt;code&gt;acts_as_taggable_on&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Community Fixes&lt;/h3&gt;
&lt;p&gt;First, &lt;a href="http://www.petercooper.co.uk/"&gt;Peter Cooper&lt;/a&gt; was kind enough to submit a patch that allows &lt;code&gt;acts_as_taggable_on&lt;/code&gt; to work with Rails 2.1&amp;#8217;s &lt;code&gt;named_scope&lt;/code&gt; when using &lt;code&gt;find_options_for_tag_counts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Secondly, the much requested support for Single Table Inheritance is finally in! It was just a matter of using a class inheritable attribute instead of a class instance variable, and big thanks to &lt;a href="http://www.nicolasblanco.fr/"&gt;slainer68&lt;/a&gt; for hunting that down and taking the time to submit a patch.&lt;/p&gt;
&lt;p&gt;If there&amp;#8217;s anything you&amp;#8217;ve hacked on to Acts As Taggable On, I urge you to submit a patch to the &lt;a href="http://mbleigh.lighthouseapp.com/projects/10116-acts-as-taggable-on"&gt;Lighthouse Project&lt;/a&gt;. I try to get new patches integrated into the codebase as quickly as possible, so please do submit anything!&lt;/p&gt;
&lt;p&gt;During the &lt;a href="http://wiki.oreillynet.com/railsconf2008/index.cgi?CommunityProjectCodeDrive"&gt;Community Code Drive&lt;/a&gt; at RailsConf two great features were added: taggers and related objects.&lt;/p&gt;
&lt;h3&gt;Taggers&lt;/h3&gt;
&lt;p&gt;Tags can now have ownership, allowing for such things as User-tracked tags and more. This was a requested feature and something that I&amp;#8217;d been looking forward to myself. Here&amp;#8217;s the usage:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  acts_as_tagger
end

class Photo &amp;lt; ActiveRecord::Base
  acts_as_taggable_on :locations
end

@some_user.tag(@some_photo, :with =&amp;gt; "paris, normandy", :on =&amp;gt; :locations)
@some_user.owned_taggings
@some_user.owned_tags
@some_photo.locations_from(@some_user)&lt;/pre&gt;
&lt;h3&gt;Find Related&lt;/h3&gt;
&lt;p&gt;Another request (and another great idea) is the ability to find related objects by similar tags. This is now available through the &lt;code&gt;@object.find_related_on_tags&lt;/code&gt; syntax:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;@bobby = User.find_by_name("Bobby")
@bobby.skill_list # =&amp;gt; ["jogging", "diving"]

@frankie = User.find_by_name("Frankie")
@frankie.skill_list # =&amp;gt; ["hacking"]

@tom = User.find_by_name("Tom")
@tom.skill_list # =&amp;gt; ["hacking", "jogging", "diving"]

@tom.find_related_on_skills # =&amp;gt; [&amp;lt;User name="Bobby"&amp;gt;,&amp;lt;User name="Frankie"&amp;gt;]
@bobby.find_related_on_skills # =&amp;gt; [&amp;lt;User name="Tom"&amp;gt;] 
@frankie.find_related_on_skills # =&amp;gt; [&amp;lt;User name="Tom"&amp;gt;] &lt;/pre&gt;
&lt;h3&gt;Gemified!&lt;/h3&gt;
&lt;p&gt;Acts As Taggable On now works as a GemPlugin in Rails. This is a new way (as of Rails 2.1) of distributing plugins as gems and having them still automatically link up and do their magic. To use it as a gem, add it to your &lt;code&gt;config/environment.rb&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;config.gem "mbleigh-acts-as-taggable-on", :source =&amp;gt; "http://gems.github.com", :lib =&amp;gt; "acts-as-taggable-on"&lt;/pre&gt;
&lt;p&gt;Now you should be able to get the latest version of the plugin just by running &lt;code&gt;rake gems:install&lt;/code&gt;. However, this hasn&amp;#8217;t been working for me so the alternative is just to install the gem directly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install mbleigh-acts-as-taggable-on --source http://gems.github.com/&lt;/pre&gt;
&lt;p&gt;Now when you run your Rails app, even though it&amp;#8217;s not in vendor/plugins it should be running! To make sure, look for this line on startup:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;** acts_as_taggable_on: initialized properly&lt;/pre&gt;
&lt;p&gt;There are still a couple of issues outstanding in Rails regarding GemPlugins (if you unpack it, it will not run the initialization properly for some reason), but I wanted to give everyone the latest and greatest way to install the plugin possible. It will still work fine using the conventional methods as well.&lt;/p&gt;
&lt;h3&gt;Community and Future&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve been really happy with the response and support of the community, and I would like to do everything possible to cultivate future participation. To that end, I have created an &lt;a href="http://www.actsascommunity.com/projects/acts-as-taggable-on"&gt;Acts As Community Project&lt;/a&gt; for &lt;code&gt;acts_as_taggable_on&lt;/code&gt; that will hopefully provide some casual communication about the project. Feel free to post on the wall or in the forums, and look out for additions soon.&lt;/p&gt;
&lt;p&gt;Finally, the area of the plugin that still needs some work is tag caching. This is not a particular area of my expertise, so I&amp;#8217;m hoping that someone from the community will write up some specs that flesh out the caching functionality in new and interesting ways.&lt;/p&gt;
&lt;p&gt;Thanks for all of the patches, and I hope you continue to enjoy using Acts As Taggable On!&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt; (6/10/08):&lt;/b&gt; The improvements keep on rolling! After writing the post, I went off on a tangent and decided to make the plugin work both traditionally and as a gem. See more details above in the &amp;#8220;Gemified&amp;#8221; section.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=zqwsOIhj"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=Lz7GK5JK"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?i=Lz7GK5JK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/mbleigh?a=yC9T9eDz"&gt;&lt;img src="http://feeds.feedburner.com/~f/mbleigh?d=52" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/mbleigh/~4/PjHalECH2cc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.mbleigh.com/2008/06/09/acts-as-taggable-on-grows-up.html</feedburner:origLink></entry>
 
 
</feed>
