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

<channel>
	<title>Dave Troy: Fueled By Randomness &#187; rails</title>
	<atom:link href="http://davetroy.com/posts/category/programming/ruby/rails-ruby/feed" rel="self" type="application/rss+xml" />
	<link>http://davetroy.com</link>
	<description>Design, Entrepreneurship, Economics and Software</description>
	<lastBuildDate>Wed, 21 Dec 2011 13:56:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>SocialDevCampEast2 Recap</title>
		<link>http://davetroy.com/posts/socialdevcampeast2-recap</link>
		<comments>http://davetroy.com/posts/socialdevcampeast2-recap#comments</comments>
		<pubDate>Fri, 07 Nov 2008 16:58:22 +0000</pubDate>
		<dc:creator>davetroy</dc:creator>
				<category><![CDATA[baltimore]]></category>
		<category><![CDATA[business]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[economics]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[social media]]></category>
		<category><![CDATA[socialdevcamp]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[trends]]></category>
		<category><![CDATA[Community]]></category>

		<guid isPermaLink="false">http://davetroy.com/?p=90</guid>
		<description><![CDATA[I&#8217;m finally recovered after a really exhausting week that included SocialDevCamp and the wild ride of Twitter Vote Report. SocialDevCampEast2 went off without a hitch on Saturday at University of Baltimore.  Once again, some of the best and brightest developers, entrepreneurs and social media gurus gathered to trade ideas and talk about the future of [...]]]></description>
			<content:encoded><![CDATA[<iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fsocialdevcampeast2-recap&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe><div class="tweetmeme_button" style="float: left; margin-right: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Fsocialdevcampeast2-recap"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Fsocialdevcampeast2-recap&amp;source=davetroy&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>I&#8217;m finally recovered after a really exhausting week that included SocialDevCamp and the wild ride of <a href="http://twittervotereport.com">Twitter Vote Report</a>.</p>
<p><img src="http://barcamp.pbwiki.com/f/socialdevcampfall-1.png" alt="" width="450" /></p>
<p>SocialDevCampEast2 went off without a hitch on Saturday at University of Baltimore.  Once again, some of the best and brightest developers, entrepreneurs and social media gurus gathered to trade ideas and talk about the future of the web.</p>
<p>One thing we try to do at SocialDevCamp is vote on the sessions, to make sure they are things that people really want to hear about, or at least size the discussions to the right rooms.  We ran 5 rooms all day in 5 sessions plus lunch, for a total of 25 sessions! Check out the <a href="http://barcamp.pbwiki.com/SocialDevCampEast2" target="_blank">wiki</a> to see the sessions that were held.</p>
<p>Personally, I enjoyed the conversation on location technology, and why location-based social networks have yet to reach critical mass.  Most folks felt that there was a technological barrier &#8212; it&#8217;s just too hard to continuously update your location with current device and battery constraints &#8212; and others questioned what incentives people have to update their locations.  We decided that those incentives probably needed to be tuned in order to see a successful location-based service emerge, and that there may also be benefit for people sharing location-related information anonymously.  Great talk, and I&#8217;m still thinking about what incentives might make LBS actually work.</p>
<p>We did a session on Twitter Vote Report, which was awesome because we were actually able to recruit some members of the crowd to do some work on the project!  Bryan Liles and John Trupiano contributed some great work to the codebase, some while sitting in the session!  We talked about the overall architecture of the project, and the fact that it was put together in just two short weeks of coding!</p>
<p>There was a good conversation about iPhone development, introducing people to the platform and answering questions about the platform.  Many seemed to be glad to get a feel for Cocoa and I wouldn&#8217;t be surprised if several of the folks there end up working on the platform!</p>
<p>Alex Hillman of Philadelphia&#8217;s Indy Hall helped to lead a discussion on co-working in Baltimore, and by the end of the session, we had actually <strong>launched</strong> co-working in Baltimore, with a mailing list and a set of great ideas for taking things forward.  Yesterday, we held our first &#8220;official&#8221; co-working meetup at Bluehouse in Baltimore; I&#8217;ll write more about the co-working initiative separately.</p>
<p>Because I wasn&#8217;t in the other sessions, I can&#8217;t say what all was said in them, but I heard good things about the conversations on data portability, source code management with Git, and crowdsourcing. If you were in one of the sessions, feel free to leave some comments here or links to your own blog!</p>
<p>Ann Bernard helped put together an awesome party for SocialDevCamp at Metro Gallery with great food from Tapas Teatro and an open bar.  And live music from Natasha El-Sergany, KADMAN, and Ra-Ra-Rasputin&#8230; A great way to end the day, and I can say that by the time it was all over, I had talked to a few hundred people and was completely exhausted!</p>
<p>This morning, Mike Subelsky, a friend and one of the organizers of the recent and fabulous <a href="http://ignitebaltimore.com">Ignite Baltimore</a> said via email, &#8220;It is not an exaggeration to say that SDCE has totally changed my life,&#8221; referring to the first SocialDevCamp held in May. Not to sound self-congratulatory, but the same is true for me.</p>
<p>SocialDevCamp is one of a few things sparking a renaissance here in the Baltimore/Washington area, giving rise to events like Ignite and to movements like co-working.  With the social media tools available now, this sort of thing is finally possible to do, and it&#8217;s hugely gratifying to see it happening!</p>
<p>See you next spring for SocialDevCampEast3!</p>
<div id="facebook_like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fsocialdevcampeast2-recap&amp;layout=standard&amp;show_faces=true&amp;width=500&amp;action=like&amp;font=segoe+ui&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:80px;" allowTransparency="true"></iframe></div><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fsocialdevcampeast2-recap&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe>]]></content:encoded>
			<wfw:commentRss>http://davetroy.com/posts/socialdevcampeast2-recap/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Twittervision Election View</title>
		<link>http://davetroy.com/posts/twittervision-election-view</link>
		<comments>http://davetroy.com/posts/twittervision-election-view#comments</comments>
		<pubDate>Fri, 26 Sep 2008 17:53:50 +0000</pubDate>
		<dc:creator>davetroy</dc:creator>
				<category><![CDATA[art]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[economics]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[social media]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[trends]]></category>
		<category><![CDATA[visualization]]></category>
		<category><![CDATA[election 2008]]></category>
		<category><![CDATA[geo]]></category>
		<category><![CDATA[map]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[twittervision]]></category>

		<guid isPermaLink="false">http://davetroy.com/?p=47</guid>
		<description><![CDATA[An hour or so ago I launched Twittervision Election View, allowing viewers to see posts to Twitter about the 2008 election in their original geographic context. Twitter launched something similar this morning, and the idea to do a political view of Twittervision has been around for a while, so it seemed natural to try to [...]]]></description>
			<content:encoded><![CDATA[<iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-election-view&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe><div class="tweetmeme_button" style="float: left; margin-right: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-election-view"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-election-view&amp;source=davetroy&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>An hour or so ago I launched <a href="http://election.twittervision.com">Twittervision Election View</a>, allowing viewers to see posts to Twitter about the 2008 election in their original geographic context.</p>
<p>Twitter launched something similar this morning, and the idea to do a political view of Twittervision has been around for a while, so it seemed natural to try to do this now and especially in advance of tonight&#8217;s debate.</p>
<p>We have some enhancements planned, and right now the site is getting a ton of traffic as people discover it&#8230; we should be able to put some more server capacity on it which should keep things steady.</p>
<p>Let me know what you think!</p>
<div id="facebook_like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-election-view&amp;layout=standard&amp;show_faces=true&amp;width=500&amp;action=like&amp;font=segoe+ui&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:80px;" allowTransparency="true"></iframe></div><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-election-view&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe>]]></content:encoded>
			<wfw:commentRss>http://davetroy.com/posts/twittervision-election-view/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twittervision API Changes</title>
		<link>http://davetroy.com/posts/twittervision-api-changes</link>
		<comments>http://davetroy.com/posts/twittervision-api-changes#comments</comments>
		<pubDate>Wed, 27 Aug 2008 08:20:56 +0000</pubDate>
		<dc:creator>davetroy</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[visualization]]></category>
		<category><![CDATA[2007]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[harvest]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[twittervision]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://davetroy.com/?p=38</guid>
		<description><![CDATA[When we first launched Twittervision in early 2007, Twitter was still a pretty small community of users (around 200,000) and only the press and the digerati were paying much attention to it. Today, with just over 1M users, Twitter is still pretty small by Internet standards, but a lot of people are paying attention to [...]]]></description>
			<content:encoded><![CDATA[<iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-api-changes&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe><div class="tweetmeme_button" style="float: left; margin-right: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-api-changes"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-api-changes&amp;source=davetroy&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>When we first launched Twittervision in early 2007, Twitter was still a pretty small community of users (around 200,000) and only the press and the digerati were paying much attention to it.</p>
<p>Today, with just over 1M users, Twitter is still pretty small by Internet standards, but <strong>a lot</strong> of people are paying attention to it.</p>
<p>Our API was designed to allow individual users to use the Twittervision location features.  A lot of people are using it.  We also had a fair number of people who were using our API as an alternative to the Twitter API and trying to harvest vast amount of data using our free API.</p>
<p>Sadly, this was restricting service to others, so we are making some changes to the API that make this kind of use no longer possible.  Those of you using the API for your individual projects or in support of client-side apps will see no changes for now &#8212; keep doing what you&#8217;re doing.</p>
<p>We do sometimes engage in licensing agreements, however, so if you are interested in licensing our data, please contact me at dave at twittervision.com.</p>
<div id="facebook_like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-api-changes&amp;layout=standard&amp;show_faces=true&amp;width=500&amp;action=like&amp;font=segoe+ui&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:80px;" allowTransparency="true"></iframe></div><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Ftwittervision-api-changes&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe>]]></content:encoded>
			<wfw:commentRss>http://davetroy.com/posts/twittervision-api-changes/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ActsAsRenderer Brings Output to Models</title>
		<link>http://davetroy.com/posts/actsasrenderer-brings-output-to-models</link>
		<comments>http://davetroy.com/posts/actsasrenderer-brings-output-to-models#comments</comments>
		<pubDate>Tue, 05 Feb 2008 20:29:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[acts_as_renderer]]></category>
		<category><![CDATA[controllers]]></category>
		<category><![CDATA[models]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://dave.popvox.com/?p=16</guid>
		<description><![CDATA[Judging by the fact that there are several posts about this topic out in the wild, and that I have come across a need for it more than once, I thought it would be helpful to wrap up this functionality into a plugin and put it out into the world. Give a warm welcome to [...]]]></description>
			<content:encoded><![CDATA[<iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Factsasrenderer-brings-output-to-models&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe><div class="tweetmeme_button" style="float: left; margin-right: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Factsasrenderer-brings-output-to-models"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Factsasrenderer-brings-output-to-models&amp;source=davetroy&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Judging by the fact that there are <a href="http://blog.yanime.org/articles/2006/08/05/rails-calling-render-outside-your-controllers">several</a> <a href="http://en.logilogi.org/MetaLogi/RenderAndActionViewOutsideRails">posts</a> about this topic out in the wild, and that I have come across a need for it more than once, I thought it would be helpful to wrap up this functionality into a plugin and put it out into the world. Give a warm welcome to <strong>ActsAsRenderer</strong>!</p>
<p>Before you go off on a tirade about the evils of violating MVC, let me first say I know the arguments and I agree with you.  However, in a world of complex systems where not everything is done via full-stack HTTP, there are legitimate reasons to output data directly from models, and ActsAsRenderer helps you do it.</p>
<p>With ActsAsRenderer, you get four cool new functions.</p>
<p>For your model class, you get <strong>render_file</strong> and <strong>render_string</strong>.  For your instances, you get <strong>render_to_file</strong> and <strong>render_to_string</strong>.</p>
<p>Probably the most common (and legitimate) use of this kind of functionality is for rendering data out of a Rails script (say with script/runner).  Since that environment is not a full-stack HTTP view of the world, it&#8217;s a real pain to render any kind of structured output.  Not anymore!  With <strong>acts_as_renderer</strong> in your model, you can render your views and give your model the voice it&#8217;s been lacking!</p>
<p>I&#8217;ve had this need come up several times.  Most recently, I built a server configuration management system using Rails.  While it is nice to preview the rendered configuration files using Rails-over-HTTP, it is also essential to be able to write those same configuration files out to the filesystem.  In another case, I had a background DRb process that needed to be able to render templated output to the filesystem.  I had to go build a mock-controller and do some pretty unsavory things; all of that would have been obviated with acts_as_renderer.</p>
<p>Now, I can simply say:</p>
<pre>class Server &lt; ActiveRecord::Base  acts_as_renderer

  def build_configuration    CLIENT_CONFIG_FILES.each do |f|      render_to_file("configs/#{f}", "#{config_dir}/#{f}.conf")    end  endend</pre>
<p>The render_to_file function renders the templates located in configs (under app/views by default) and writes them to the files specified in the config_dir;  it&#8217;s also smart enough to know that render_to_file is being called from a &#8216;server&#8217; instance and sets @server accordingly.  So my templates in configs are simply:</p>
<pre>; Configuration Snippet for Server &lt;%=@server.description%&gt;

&lt;%= render :partial =&gt; 'configs/queue', :collection =&gt; @server.queues %&gt;</pre>
<p>Please do <strong>think</strong> before using this plugin.  It can be used for some seriously evil violations of good MVC design practice, and you are responsible for your own actions.  However, this can also be used to make your existing designs *much* more robust and elegant, and I encourage you to use it where that is true.</p>
<p>It&#8217;s ready to drop in.  Everything is there, including tests.  Enjoy!</p>
<p><strong>NOTE:</strong> Version 1.0 only supported Rails 2.0; I just added version 1.01 which will work with either Rails 1.2.x or 2.0.x.  Please feel free to ping me with any questions.</p>
<p><a href="http://rubyforge.org/projects/actsasrenderer/">acts_as_renderer</a> at RubyForge</p>
<div id="facebook_like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Factsasrenderer-brings-output-to-models&amp;layout=standard&amp;show_faces=true&amp;width=500&amp;action=like&amp;font=segoe+ui&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:80px;" allowTransparency="true"></iframe></div><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Factsasrenderer-brings-output-to-models&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe>]]></content:encoded>
			<wfw:commentRss>http://davetroy.com/posts/actsasrenderer-brings-output-to-models/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Automatic Asset Minimization and Packaging with Rails 2.0.x</title>
		<link>http://davetroy.com/posts/automatic-asset-minimization-and-packaging-with-rails-20x</link>
		<comments>http://davetroy.com/posts/automatic-asset-minimization-and-packaging-with-rails-20x#comments</comments>
		<pubDate>Sat, 29 Dec 2007 15:11:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[ruby rails css javascript minimization monkey patch]]></category>

		<guid isPermaLink="false">http://dave.popvox.com/?p=11</guid>
		<description><![CDATA[With the recent release of Rails 2.0, many of us are reviewing our approaches to common problems. Many new features have been added to Rails, and some old tricks are either no longer necessary or no longer work. I am developing a project with Rails 2.0 and am getting close to putting it into production. [...]]]></description>
			<content:encoded><![CDATA[<iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fautomatic-asset-minimization-and-packaging-with-rails-20x&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe><div class="tweetmeme_button" style="float: left; margin-right: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Fautomatic-asset-minimization-and-packaging-with-rails-20x"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Fautomatic-asset-minimization-and-packaging-with-rails-20x&amp;source=davetroy&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>With the recent release of Rails 2.0, many of us are reviewing our approaches to common problems.   Many new features have been added to Rails, and some old tricks are either no longer necessary or no longer work.</p>
<p>I am developing a project with Rails 2.0 and am getting close to putting it into production.  A recurring issue for today&#8217;s web developers is that of <strong>asset packaging</strong>, or the combination of multiple site assets into a single file.  Specifically, we&#8217;re talking about Javascript and CSS.</p>
<p>A given &#8220;Web 2.0&#8243; (a term I wish had recently been found dead in a cramped apartment in Brooklyn) site might have a half dozen Javascript or CSS files to deliver to a user, and web browsers are not all that efficient at retrieving them.  Each one requires a separate TCP connection to the server, and many browsers are only capable of getting two of these files concurrently.  This means delays for your users.</p>
<p>In Rails 2.0 (and previously in Edge Rails), it&#8217;s possible to combine multiple Javascript and CSS files using the <strong>javascript_include_tag</strong> and <strong>stylesheet_link_tag</strong> functions in your <em>html.erb</em> files;  simply add <strong>:cache =&gt; true</strong> to the parameters like this:</p>
<pre><code>&lt;%= javascript_include_tag 'prototype', 'effects', :cache =&gt; true %&gt;&lt;%= stylesheet_link_tag 'main', 'shop', 'form', :cache =&gt; true %&gt;</code></pre>
<p>With <strong>:cache =&gt; true</strong> and when running in your production environment, Rails will automatically combine your Javascript and CSS assets into single files (all.js and all.css, respectively) and significantly reduce your site&#8217;s load time.</p>
<p>However, this really only solves part of the problem.  A common technique used to further improve site performance is to compress Javascript and CSS by removing unnecessary whitespace and comments.  I am not sure why this wasn&#8217;t included as part of Rails&#8217; built-in caching features, but it seemed to me it should be easy to add.</p>
<p>Turns out I was mostly right.  Google &#8220;javascript minimization&#8221; (or <em>minification</em>) and you&#8217;ll see it&#8217;s a pretty hot topic.  The Asset Packager plugin from Scott Becker does this, as well as CSS compression, but is targeted at Rails 1.x and doesn&#8217;t really make sense in the face of Rails 2.0.</p>
<p>So I set out to solve this problem in an elegant way for Rails 2.0.  Asset Packager uses a Ruby script called <strong>jsmin.rb</strong> by Uladzislau Latynski which is based on <strong>jsmin.c</strong> by Douglas Crockford.  The thing is, jsmin.rb is not a class or library, but rather a standalone executable that operates on <strong>stdin</strong> and <strong>stdout</strong>.  Asset Pacakger actually <strong>forks a ruby shell process</strong> to do its Javascript minimization, and this seemed like folly if it could be done internal to Rails.</p>
<p>Accordingly, I modified <strong>jsmin.rb</strong> to operate as a singleton class and with a class method you could pass Javascript data to.  Then it was simply a matter of monkey patching this function into <strong>ActionView::Helpers::AssetTagHelper</strong>, home of <strong>javascript_include_tag</strong> and <strong>stylesheet_link_tag</strong>.</p>
<p>I also wanted to add in CSS compression, which turned out to be easy.  The <strong>javascript_include_tag</strong> and <strong>stylesheet_link_tag</strong> functions both use the same underlying functions to package their assets, so it was a simple case of replacing them with equivalents that do compression appropriately, based on whether we are dealing with CSS or JS.</p>
<p><em>config/initializers/javascript_minimization.rb:</em></p>
<pre><code>module ActionView  module Helpers    module AssetTagHelper      require 'jsminlib'

      def compress_css(source)        source.gsub!(/\s+/, " ")           # collapse space        source.gsub!(/\/\*(.*?)\*\/ /, "") # remove comments        source.gsub!(/\} /, "}\n")         # add line breaks        source.gsub!(/\n$/, "")            # remove last break        source.gsub!(/ \{ /, " {")         # trim inside brackets        source.gsub!(/; \}/, "}")          # trim inside brackets      end

      def get_file_contents(filename)        contents = File.read(filename)        if filename =~ /\.js$/          JSMin.minimize(contents)        elsif filename =~ /\.css$/          compress_css(contents)        end      end

      def join_asset_file_contents(paths)        paths.collect { |path|          get_file_contents(File.join(ASSETS_DIR, path.split("?").first)) }.join("\n\n")      end

    end  endend</code></pre>
<p>By simply modifying <strong>join_asset_file_contents</strong> to use our new function <strong>get_file_contents</strong> instead of <strong>File.read</strong>, we quickly get to the heart of the matter.  CSS files get <strong>compress_css</strong> run on them, while Javascript files get <strong>JSMin.minimize</strong> run on them.  Your <strong>:cache =&gt; true</strong> Javascript and CSS assets will now be gloriously combined and compressed!</p>
<p>Note that the above monkey patch requires <a href="http://www.popvox.com/jsminlib.rb">jsminlib.rb</a>, which you can download here.  It is just a modified version of the original jsmin.rb, and you will want to put it into your Rails lib directory.</p>
<p>A good next step would be to further enhance <strong>get_file_contents</strong> to do Javascript obfuscation, which allows for the replacement of variable names and thus even further compression;  it also tends to make Javascript code nearly incomprehensible and thus harder to steal, which may be desirable for some developers.  I haven&#8217;t found any native Ruby ways to do this yet, but it seems to me that this would be a good place for a C extension (or similar), and that this should all be put into a tiny and lightweight plugin.</p>
<p>I&#8217;m always amazed at how easy it is to bend Rails (and Ruby) to one&#8217;s will, and in this case it&#8217;s really quite elegant and straightforward.  I&#8217;d love to hear your ideas about how to take this idea forward, potentially even including it in Rails itself.</p>
<p>Download the files here:</p>
<ul>
<li><a href="http://www.popvox.com/jsminlib.rb">lib/jsminlib.rb</a></li>
<li><a href="http://www.popvox.com/javascript_minimization.rb">config/initializers/javascript_minimization.rb</a></li>
</ul>
<div id="facebook_like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fautomatic-asset-minimization-and-packaging-with-rails-20x&amp;layout=standard&amp;show_faces=true&amp;width=500&amp;action=like&amp;font=segoe+ui&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:80px;" allowTransparency="true"></iframe></div><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fautomatic-asset-minimization-and-packaging-with-rails-20x&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe>]]></content:encoded>
			<wfw:commentRss>http://davetroy.com/posts/automatic-asset-minimization-and-packaging-with-rails-20x/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MoMA NY Selects Twittervision &amp; Flickrvision</title>
		<link>http://davetroy.com/posts/moma-ny-selects-twittervision-flickrvision</link>
		<comments>http://davetroy.com/posts/moma-ny-selects-twittervision-flickrvision#comments</comments>
		<pubDate>Sat, 06 Oct 2007 15:11:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[art]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[social media]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[trends]]></category>
		<category><![CDATA[visualization]]></category>
		<category><![CDATA[APIs]]></category>
		<category><![CDATA[flickrvision]]></category>
		<category><![CDATA[mashups]]></category>
		<category><![CDATA[MoMA]]></category>
		<category><![CDATA[twittervision]]></category>

		<guid isPermaLink="false">http://dave.popvox.com/?p=6</guid>
		<description><![CDATA[Yesterday, I received final confirmation that the Museum of Modern Art in New York has selected my mash-ups twittervision.com and flickrvision.com for its 2008 exhibition Design and the Elastic Mind. I&#8217;m certainly very flattered to be included and have never considered myself to be an artist. I didn&#8217;t seek out MoMA on this. I am [...]]]></description>
			<content:encoded><![CDATA[<iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fmoma-ny-selects-twittervision-flickrvision&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe><div class="tweetmeme_button" style="float: left; margin-right: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Fmoma-ny-selects-twittervision-flickrvision"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fdavetroy.com%2Fposts%2Fmoma-ny-selects-twittervision-flickrvision&amp;source=davetroy&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Yesterday, I received final confirmation that the Museum of Modern Art in New York has selected my mash-ups <a href="http://twittervision.com">twittervision.com</a> and <a href="http://flickrvision.com">flickrvision.com</a> for its 2008 exhibition <a href="http://www.moma.org/exhibitions/exhibitions.php?id=5632&amp;ref=calendar">Design and the Elastic Mind</a>.</p>
<p>I&#8217;m certainly very flattered to be included and have never considered myself to be an artist.  I didn&#8217;t seek out MoMA on this.  I am just very, very happy to have an opportunity to participate in a small way in the ongoing dialog about what technology means for humanity.  Crap.  Now I sound like an artist.</p>
<p>Incidentally, this means that twittervision.com and flickrvision.com are the first ever Ruby On Rails apps to be included in a major art exhibition.  I already told DHH.</p>
<p>Anyway, at RailsConf Europe a few weeks ago, Dave Thomas&#8217; keynote speech emphasized the role of software designers as artists.  He said, &#8220;treat your projects as though they are artworks, and sign your name to them.&#8221;  Or pretty close to it.  I think this is incredibly valuable advice for software designers today.</p>
<p>We&#8217;re past the days of using machines as amplifiers of our physical efforts.  It&#8217;s not enough to jam more features into code just so we can eliminate one more position on the assembly line.  We&#8217;re at a point where the machines can help amplify our imaginations.</p>
<p>Today, creativity and imagination (what some folks are calling the right brain) are becoming the key drivers of software and design.  With imagination, we can see around the corners of today&#8217;s most pressing challenges.  While technical skill is certainly valuable, if it&#8217;s applied to the wrong problems, it&#8217;s wasted effort.</p>
<p>Creativity, imagination, and artistry help us identify the areas where we should put our efforts.  They help us see things in new ways.</p>
<p>Everywhere I turn (perhaps partly because I am a Rubyist), I hear discussions of Domain Specific Languages, and of framing our problems in the right grammars.</p>
<p>This is hugely valuable because the creative part of our brain thinks in terms of semantics, grammars, and symbols.  If we can&#8217;t get the words right, our imaginations can&#8217;t engage.</p>
<p>Everything stays stuck in the left side of our brains when we have to jump through hoops to please some particular language or development environment.</p>
<p>I hope you all will come out to see <strong>Design and the Elastic Mind</strong> when it opens at NYC MoMA, Feb 24 &#8211; May 12 2008.  I&#8217;m not sure how we&#8217;re going to present the sites but we&#8217;re going to see if we can get some partners and sponsors involved to do something really beautiful.</p>
<p>And again, thanks to MoMA for the selection.  And here&#8217;s to creativity, imagination, and artistry as the next big thing in software design!</p>
<div id="facebook_like"><iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fmoma-ny-selects-twittervision-flickrvision&amp;layout=standard&amp;show_faces=true&amp;width=500&amp;action=like&amp;font=segoe+ui&amp;colorscheme=light&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:80px;" allowTransparency="true"></iframe></div><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fdavetroy.com%2Fposts%2Fmoma-ny-selects-twittervision-flickrvision&amp;layout=standard&amp;show_faces=true&amp;width=280&amp;action=like&amp;colorscheme=light&amp;height=30' scrolling='no' frameborder='0' style='border:none; overflow:hidden; height:30px' allowTransparency='true'></iframe>]]></content:encoded>
			<wfw:commentRss>http://davetroy.com/posts/moma-ny-selects-twittervision-flickrvision/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

