<?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>Push cx &#187; Rails</title>
	<atom:link href="http://push.cx/tag/rails/feed" rel="self" type="application/rss+xml" />
	<link>http://push.cx</link>
	<description>A traveling geek&#039;s blog on development, games, and the web</description>
	<lastBuildDate>Fri, 14 Oct 2011 10:24:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Rewriting My Competitors</title>
		<link>http://push.cx/2011/rewriting-my-competitors</link>
		<comments>http://push.cx/2011/rewriting-my-competitors#comments</comments>
		<pubDate>Sat, 09 Jul 2011 10:48:23 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Allabrilyn]]></category>
		<category><![CDATA[code smells]]></category>
		<category><![CDATA[Fantasy Adventure]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[sessions]]></category>
		<category><![CDATA[so play we all]]></category>

		<guid isPermaLink="false">http://push.cx/?p=1811</guid>
		<description><![CDATA[It&#8217;s really clear that the polls So Play We All are measuring progress. When we have a quiet week, there&#8217;s a lot fewer votes. This week, there were 4, evenly split between Luke and I. The SPWA site doesn&#8217;t have code to handle ties so it highligted me as winning, which I guess means the [...]]]></description>
			<content:encoded><![CDATA[<p>
  It&#8217;s really clear that the polls <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3NvcGxheXdlYWxsLmNvbQ==">So Play We All</a> are measuring progress. When we have a quiet week, there&#8217;s a lot fewer votes. This week, there were 4, evenly split between Luke and I. The SPWA site doesn&#8217;t have code to handle ties so it highligted me as winning, which I guess means the bugfix is not <em>my</em> problem. :)
</p>

<p>
  Luke <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Jsb2cuZmFudGFzeWFkdmVudHVyZWdhbWUuY29tLzIwMTEvMDcvMDYvYS1zcHJpbmctYnViYmxlcy11cC8=">laid down code</a> for cards. I know I&#8217;m helping the enemy, but I&#8217;ve got to tweak it. His code is:
</p>

<pre>&nbsp;
class CardController &lt; ApplicationController
  def play
    play_sym = <span style="color: #ff0000;">"play_#{@card}"</span>.<span style="">intern</span> <span style="color: #808080; font-style: italic;"># PH: this should be .to_sym</span>
    self.<span style="">send</span><span style="color: #66cc66;">&#40;</span>play_sym<span style="color: #66cc66;">&#41;</span>
    render :action =&gt; play_sym <span style="color: #b1b100;">and</span> <span style="color: #000066;">return</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def pocket
    pocket_sym = <span style="color: #ff0000;">"pocket_#{@card}"</span>.<span style="">intern</span>
    self.<span style="">send</span><span style="color: #66cc66;">&#40;</span>pocket_sym<span style="color: #66cc66;">&#41;</span>
  <span style="color: #b1b100;">end</span> <span style="color: #808080; font-style: italic;"># PH: no explicit render here? Feels like a paste error</span>
&nbsp;
  protected
&nbsp;
  <span style="color: #808080; font-style: italic;"># plays</span>
  def play_roland
    <span style="color: #808080; font-style: italic;"># Play the game to see what happens when you play the Roland card!</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def play_water
    <span style="color: #808080; font-style: italic;"># Play the game to see what happens when you play the Water card!</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  <span style="color: #808080; font-style: italic;"># pockets</span>
  def pocket_roland
    <span style="color: #808080; font-style: italic;"># Play the game to see what happens when you pocket the Roland card!</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def pocket_water
    <span style="color: #808080; font-style: italic;"># Play the game to see what happens when you pocket the Water card!</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
<span style="color: #b1b100;">end</span></pre>

I&#8217;d write this code as:

<pre>&nbsp;
class CardController &lt; ApplicationController
  <span style="color: #808080; font-style: italic;"># I'm guessing from usage above @card is just the name for a card as a string</span>
  <span style="color: #808080; font-style: italic;"># and that it's loaded from the url by a filter, note that I use it differently.</span>
  before_filter :load_card
  after_filter :default_render_card
  
  def play
    <span style="color: #0000ff;">@card</span>.<span style="">play</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def pocket
    <span style="color: #0000ff;">@card</span>.<span style="">pocket</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  protected
&nbsp;
  def load_card
    <span style="color: #0000ff;">@name</span> = params<span style="color: #66cc66;">&#91;</span>:card<span style="color: #66cc66;">&#93;</span>
    <span style="color: #0000ff;">@card</span> = <span style="color: #ff0000;">"card/#{@name}"</span>.<span style="">camelize</span>.<span style="">constantize</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def default_render_card
    render :template =&gt; <span style="color: #ff0000;">"cards/#{request.action}/#{@name}"</span> <span style="color: #b1b100;">unless</span> performed?
  <span style="color: #b1b100;">end</span>
end
&nbsp;
<span style="color: #808080; font-style: italic;"># add in config/application.rb:</span>
module Oaqn
  class Application &lt; Rails::<span style="color: #006600;">Application</span>
    config.<span style="">autoload_paths</span> += <span style="color: #0000ff;">%W</span><span style="color: #66cc66;">&#40;</span><span style="color: #808080; font-style: italic;">#{config.root}/app/cards)</span>
  <span style="color: #b1b100;">end</span>
end
&nbsp;
<span style="color: #808080; font-style: italic;"># and then create app/cards/roland.rb:</span>
module Card
  module Roland
    def pocket
      <span style="color: #808080; font-style: italic;"># code for pocketing</span>
    <span style="color: #b1b100;">end</span>
&nbsp;
    def play
      <span style="color: #808080; font-style: italic;"># code for playing</span>
    <span style="color: #b1b100;">end</span>
  <span style="color: #b1b100;">end</span>
end</pre>

<p>
  So now the cards each get a source file to themselves, templates have their own per-action dirs (better swapped to per-card dirs, if there are more actions), there&#8217;s less duplicated code, and it&#8217;s far easier to test these smaller pieces. The only thing missing from this example is the fact that Luke may have to pass some game state into the methods. As long as there&#8217;s not too much it&#8217;s probably worth being explicit about.
</p>

<p class="update">
2011-07-09: Luke actually used this code and found it didn&#8217;t work as written. I found <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MDc0ODMwL2FkZGluZy1saWItdG8tY29uZmlnLWF1dG9sb2FkLXBhdGhzLWkNCm4tcmFpbHMtMy1kb2VzLW5vdC1hdXRvbG9hZC1teS1tb2R1bGU=">an explanation</a>; either add &#8216;app&#8217; to <kbd>autoload_paths</kbd> instead of &#8216;app/cards&#8217;, or drop the Card wrapper.
</p>

<p>
  Meanwhile, in the past, Jim <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Jsb2cuYWxsYWJyaWx5bi5jb20vY29udGVudC9jbGFzcy1zZXNzaW9u">wrote some PHP</a>, and I&#8217;m not touching that language.
</p>

<p>
  No, in seriousness, Jim talked about why he has some identifiers surrounded by __ (which I&#8217;d called <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAxMS9zbWFsbC1zdGVwcw==">python poisoning</a>). I haven&#8217;t dug into his code (again, PHP), but it looks like it might be an <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2MyLmNvbS9jZ2kvd2lraT9JbkJhbmRTaWduYWw=">InBandSignal</a> to reuse Events as framework steps.
</p>

<p>
  And then he talks about session fixation attacks, which are have been protected against out-of-the-box on PHP with the <kbd>session.use_only_cookies</kbd> setting for a while. I was a bit confused, I&#8217;m pretty sure he&#8217;s actually describing session capture attacks. Oh, and there was some other stuff about writing code to store sessions in the database. If you&#8217;re curious, Jim, here&#8217;s the code for a Rails app to do that, which appears commented-out in the stock config file for your editing convenience:
</p>

<pre>&nbsp;
  Oaqn::<span style="color: #006600;">Application</span>.<span style="">config</span>.<span style="">session_store</span> :active_record_store</pre>

<p>
  It includes support out of the box for keeping sessions in cookies (encrypted, of course), your SQL database via ActiveRecord, or Memcached. I&#8217;m curious, how much of your budget did you spend storing sessions?
</p>
 <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=1811" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2011/rewriting-my-competitors/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>From Fixtures to Factories</title>
		<link>http://push.cx/2010/from-fixtures-to-factories</link>
		<comments>http://push.cx/2010/from-fixtures-to-factories#comments</comments>
		<pubDate>Tue, 06 Jul 2010 19:33:02 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[factories]]></category>
		<category><![CDATA[factory_girl]]></category>
		<category><![CDATA[fixtures]]></category>
		<category><![CDATA[Mocha]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://push.cx/?p=1428</guid>
		<description><![CDATA[Automated tests need example data, and it&#8217;s a pain to have to construct a complete object in every test, especially when there are a lot of non-optional fields. The standard improvement is to use fixtures, a file with some example data, that your tests can load by giving the name of a fixture. Here&#8217;s one [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=L3RhZy90ZXN0aW5n">Automated tests</a> need example data, and it&#8217;s a pain to have to construct a complete object in every test, especially when there are a lot of non-optional fields.
</p>

<p>
The standard improvement is to use fixtures, a file with some example data,
that your tests can load by giving the name of a fixture. Here&#8217;s one of the
fixtures for a <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20=">gamer</a>:
</p>

<pre>
alice: # alice is heavily involved
  id: 1
  mail: alice@example.com
  handle: alice
  password: red queen
  teaser: Follow the white rabbit.
  profile: Not so plain, after all.
  homepage: http://www.example.com
  jabber: alice@example.org
  location_id: 3
  last_login: 2006-10-30 11:56:08
  created_at: 2006-10-30 11:56:08
  location_at: 2006-10-30 11:56:08
  tag_text: dnd, wod
  mail_on_message: true
  mail_on_nearby_discussion: true
</pre>

<p>
This is straightforward, but <kbd>location_id</kbd> is the id of another fixture in another file. As you can imagine it&#8217;s pretty easy to get them out-of-sync and break some tests. I end up leaving little <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2MyLmNvbS9jZ2kvd2lraT9Ub05lZWRDb21tZW50cw==">comments</a> in the YAML to remind myself of the cross-reference.
</p>

<p>
It&#8217;s awfully tempting to reuse fixtures from test to test. Maybe Alice was written to test logging in with a username and password and next I&#8217;m writing the test of logging in with an email address and a password. I could copy and paste Alice to another fixture to reuse in that test, but as a programmer I have a pathological aversion to copy and paste. Alice is going to get reused (most of those fields are optional and were used by very different tests), and after this happens a few times it&#8217;s hard to change a fixture without breaking an unrelated test.
</p>

<p>
I&#8217;ve gotten a lot of use out of fixtures as I&#8217;ve developed the habit of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwOS93aHktaS13cml0ZS10ZXN0cw==">testing all my code</a>, but reuse has made my tests somewhat brittle. After a bit of research, I&#8217;ve moved over to using factories.
</p>

<p>
Here&#8217;s the factory for a gamer:
</p>

<pre>&nbsp;
Factory.<span style="">sequence</span> :handle <span style="color: #66cc66;">&#123;</span> |n| <span style="color: #ff0000;">"Gamer_#{n}"</span> <span style="color: #66cc66;">&#125;</span>
&nbsp;
Factory.<span style="">define</span> :gamer <span style="color: #b1b100;">do</span> |g|
  g.<span style="">handle</span> <span style="color: #66cc66;">&#123;</span> Factory.<span style="">next</span> :handle <span style="color: #66cc66;">&#125;</span>
  g.<span style="">mail</span> <span style="color: #66cc66;">&#123;</span> |m| <span style="color: #ff0000;">"#{m.handle}@example.com"</span> <span style="color: #66cc66;">&#125;</span>
  g.<span style="">password</span> <span style="color: #ff0000;">'secret'</span>
<span style="color: #b1b100;">end</span></pre>

<p>
Only the essential, required fields are listed. Using this simple template, the tests themselves specify the values of the fields they&#8217;ll be testing.
</p>

<pre>&nbsp;
def test_login_with_valid_username_and_password
  gamer = Gamer.<span style="">create</span> :handle =&gt; <span style="color: #ff0000;">'Alice'</span>, :password =&gt; <span style="color: #ff0000;">'red queen'</span>
  ...
<span style="color: #b1b100;">end</span>
def test_login_with_valid_email_and_password
  gamer = Gamer.<span style="">create</span> :mail =&gt; <span style="color: #ff0000;">'alice@example.com'</span>, :password =&gt; <span style="color: #ff0000;">'red queen'</span>
  ...
<span style="color: #b1b100;">end</span></pre>

<p>
Ideally, changing a fixture wouldn&#8217;t break any tests at all. And <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpdGh1Yi5jb20vdGhvdWdodGJvdC9mYWN0b3J5X2dpcmw=">factory_girl</a> (what I&#8217;m using for factories in Rails) makes associations easy:
</p>

<pre>&nbsp;
Factory.<span style="">define</span> :post <span style="color: #b1b100;">do</span> |p|
  p.<span style="">association</span> :discussion, :factory =&gt; :discussion
  p.<span style="">association</span> :poster, :factory =&gt; :gamer
  p.<span style="">created_at</span> Time.<span style="">now</span>.<span style="">utc</span>
  p.<span style="">body</span> <span style="color: #ff0000;">"Post Body"</span>
<span style="color: #b1b100;">end</span></pre>

<p>
Now my tests include the specific data they care about, making them easier to understand and improve. And they don&#8217;t interrelate, so they&#8217;re much more reliable. I do still use fixtures, but now they&#8217;re exclusively for tests that need to deal with real-world examples.
</p>
 <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=1428" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2010/from-fixtures-to-factories/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>NearbyGamers To-Do List</title>
		<link>http://push.cx/2009/nearbygamers-to-do-list</link>
		<comments>http://push.cx/2009/nearbygamers-to-do-list#comments</comments>
		<pubDate>Thu, 12 Feb 2009 15:27:19 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Biz]]></category>
		<category><![CDATA[aggregation]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[groups]]></category>
		<category><![CDATA[NearbyGamers]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[performance monitoring]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[stores]]></category>
		<category><![CDATA[to-do]]></category>

		<guid isPermaLink="false">http://push.cx/?p=666</guid>
		<description><![CDATA[NearbyGamers has been growing steadily without a lot of direct action on my part. I&#8217;ve been bugfixing and moderating, but aside from some performance improvements in November, it&#8217;s been quite a while since its had any user-visible improvements. Mostly this has been because I keep distracting myself with side projects: they&#8217;re deceptively simple to start [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20=">NearbyGamers</a> has been growing steadily without a lot of direct action on my part. I&#8217;ve been bugfixing and moderating, but aside from some performance improvements in November, it&#8217;s been quite a while since its had any user-visible improvements. Mostly this has been because I keep distracting myself with side projects: they&#8217;re deceptively simple to start but always have some area(s) of significant non-obvious complexity and a need for time-consuming polishing and refinement. I&#8217;m going to <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDkvc21hbGwtcGxhbnM=">finish them off</a> and then give attention to NearbyGamers.
</p>

<p>
What I plan:
</p>

<dl>

<dt>Performance Improvements</dt>
<dd>Despite what I did in November, some parts are still laggy; <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5iaW5nb2NhcmRjcmVhdG9yLmNvbS9hcnRpY2xlcy9kZXZlbG9waW5nLXNob3BwaW5nLWNhcnQuaHRt">on the Internet if it isn&#8217;t instant, it&#8217;s slow</a>. I&#8217;m aware of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5maXZlcnVucy5jb20vcHJvZHVjdHMvbWFuYWdl">FireRuns Manage</a> and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25ld3JlbGljLmNvbS9SUE0uaHRtbA==">NewRelic&#8217;s RPM</a> for production performance monitoring. I&#8217;ll almost certainly end up with Manage (30-day trial) because RPM&#8217;s trial (30 minutes of data, useless for a small/young/low-traffic site) is so weak, but I&#8217;d really appreciate comments if anyone knows of other good tools.</dd>

<dt>News Aggregation</dt>
<dd>There are a lot of tabletop gaming/board game/RPG blogs and hand-edited news sites, and I think NearbyGamers would do well to aggregate those similar to Reddit/Digg. It&#8217;d bring gamers back to the site more regularly (rather than the common &#8216;signup, leave for a few months until someone new messages you&#8217;) and drive discussion, which is the best way to meet folks.</dd>

<dt>Groups</dt>
<dd>One of the biggest uses of the discussion forum is folks trying to organize gaming groups. Now that I&#8217;ve seen this happen a few times, I can build proper support for groups: a marker on the map, a dedicated forum per group, and advertising open slots for gamers, to start. Then there&#8217;s the next obvious feature for them:</dd>

<dt>Events</dt>
<dd>With or without a group, it should be possible to display upcoming events on the maps. List date and time, attendance information, link to a homepage if one exists, maybe have a dedicated forum.</dd>

<dt>Stores</dt>
<dd>It would also be good to list gaming stores on the map, which are oddly often difficult to find. This especially relates to the previous; I&#8217;d love to see what events my local stores have on their calendars. I also think gaming stores are nicer for browsing than websites, I&#8217;ve found so many interesting random games at stores that I wouldn&#8217;t have glanced at online. I&#8217;d like NearbyGamers to help stores stay in business and grow because they incubate local gaming communities.</dd>

</dl>

<p>
After I finish with the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDkvc21hbGwtcGxhbnM=">small projects</a>, I think these features will probably take me a solid month to implement. NearbyGamers is developing a regular community, and I have a responsibility to help it thrive. What I&#8217;ll do afterwards is its own couple hundred words for tomorrow.
</p>

<p>
Next: <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDkvd2ViLWdhbWU=">The Startup Project That Lacks Even a Working Title</a>
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=666" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2009/nearbygamers-to-do-list/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OpenOffice.org Losing Viability</title>
		<link>http://push.cx/2009/openofficeorg-losing-viability</link>
		<comments>http://push.cx/2009/openofficeorg-losing-viability#comments</comments>
		<pubDate>Sat, 24 Jan 2009 16:23:25 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[OpenOffice.org]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://push.cx/?p=622</guid>
		<description><![CDATA[OpenOffice.org developer Michael Meeks analyzed 2008 commit data to show that the project is losing steam: decreasing numbers of commits, developers, and companies. He rhetorically asks about how the project is losing technical quality: Why is my bug not fixed ? why is the UI still so unpleasant ? why is performance still poor ? [...]]]></description>
			<content:encoded><![CDATA[<p>
OpenOffice.org developer Michael Meeks <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5nbm9tZS5vcmcvfm1pY2hhZWwvYmxvZy9vb28tY29tbWl0LXN0YXRzLTIwMDguaHRtbA==">analyzed 2008 commit data</a> to show that the project is losing steam: decreasing numbers of commits, developers, and companies. He rhetorically asks about how the project is losing technical quality:
</p>

<blockquote>
Why is my bug not fixed ? why is the UI still so unpleasant ? why is performance still poor ? why does it consume more memory than necessary ? why is it getting slower to start ? why ? why ? &#8211; the answer lies with developers: Will you help us make OpenOffice.org better ?
</blockquote>

<p>
Meeks identifies the lack of growth in the community as the core problem and his suggestions for improving the software product are about redesigning the community to be more responsive to developers, to welcome newbies better, and to simplify the act of contributing. Notably, he doesn&#8217;t suggest a single technical change for improving bugs, the UI, performance, or other features.
</p>

<p>
Maybe this is a better example than mine of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDkvb3Blbi1zb3VyY2UtY29tbXVuaXRpZXM=">Django and Rails</a>: developers don&#8217;t tend to get irrationally competitive about office productivity suites and stop listening like they do web frameworks. (This is part of why OOo is in more trouble than Django.) The point is the same, though: a healthy, active community is the only guarantee of a an open source project&#8217;s viability. Community determines whether a project keeps up with its competition and redefines the limits of its field, or maintains the status quo, or becomes unreliable and unusable.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=622" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2009/openofficeorg-losing-viability/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Open Source Communities</title>
		<link>http://push.cx/2009/open-source-communities</link>
		<comments>http://push.cx/2009/open-source-communities#comments</comments>
		<pubDate>Mon, 19 Jan 2009 13:28:53 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://push.cx/?p=554</guid>
		<description><![CDATA[Open source projects should be judged as much by their community as by their technological achievements. The code tells you what it&#8217;s good for, but the community tells you what its future is. Communities need to be active to continue improving the project, deal with bugs and changes to their ecosystem. If no one is [...]]]></description>
			<content:encoded><![CDATA[<p>
Open source projects should be judged as much by their community as by their technological achievements. The code tells you what it&#8217;s good for, but the community tells you what its future is.
</p>

<p>
Communities need to be active to continue improving the project, deal with bugs and changes to their ecosystem. If no one is interested enough to talk about the project, none of that will happen. Newcomers need to meet experienced users to be sold on why to use the software, to get help as they learn their way around, to maybe be drawn into contributing to the project itself.
</p>

<p>
Some communities are maladjusted. They <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5zaGlya3kuY29tL3dyaXRpbmdzL2dyb3VwX2VuZW15Lmh0bWw=">self-defeat</a> (see the section on Bion&#8217;s support groups), they lack plans or goals, they abuse newbies to keep from growing or changing, they&#8217;re more interested in bringing something down or defending turf than building up their own project. Some successful projects start <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dldHRpbmdyZWFsLjM3c2lnbmFscy5jb20vY2gwMl9IYXZlX2FuX0VuZW15LnBocA==">with a grudge to pick</a>, but most that do so fail to develop their own identify, and you can hear that in a cacophony of blame and flames in their social spaces.
</p>

<p>
Productivity is the best way to tell if a community is well. Even if it doesn&#8217;t have regular releases, it needs explicit plans on a reasonable schedule to meet measurable goals. Good software is produced by careful and deliberate iteration.
</p>

<p>
All well and good, but what about the slugfest between Django and Rails? When do we get to the part where I reveal myself as an irrational, deceptive propagandist because I say anything nice about the project you don&#8217;t prefer? Better question: why is there so much vitrol between the two?
</p>

<p>
The two are far more alike than dissimilar: extracted from projects that were created in similar dynamic languages from late 2003 through 2004, their core functionality was routing URLs to templates rendered with data retrieved with an ORM.
</p>

<p>
The biggest early difference is in these two contemporaneous blog posts: <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kamFuZ29wcm9qZWN0LmNvbS93ZWJsb2cvMjAwNS9qdWwvMTUvY2hpcHkv">Django releases</a>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy4zN3NpZ25hbHMuY29tL3N2bi9hcmNoaXZlczIvcnVieV9vbl9yYWlsc190dXJuc18xLnBocA==">Rails turns 1</a>. Django was wrongly seen as a Python copy of Rails on its release, though it&#8217;s just a case of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db252ZXJnZW50X2V2b2x1dGlvbg==">convergent evolution</a>: to solve similar problems they developed along the same lines.
</p>

<p>
If success is binary, both Rails and Django are successes. They&#8217;re strong, reliable tools for building websites quickly. They are their respective languages&#8217; leading web frameworks. Speaking personally, I enjoy working daily in both.
</p>

<p>
If success is relative, Rails is far more successful than Django. By any measure I can take, the Rails community is at least ten times larger. For example, Indeed has more jobs and Google Trends shows more searches:
</p>

<a style=\"float: right\" href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5nb29nbGUuY29tL3RyZW5kcz9xPXB5dGhvbitkamFuZ28lMkMrcnVieStyYWlscw=="><img src="/wp-content/uploads/2009/01/google_trends-150x150.png" ></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5pbmRlZWQuY29tL2pvYnRyZW5kcz9xPXJhaWxzJTJDK2RqYW5nbyYjMDM4O2w9"><img src="/wp-content/uploads/2009/01/indeed-150x150.png" ></a>


<p>
And yesterday I posted about the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwOS9kamFuZ28tdnMtcmFpbHMtdGhlLWRlYWQtdHJlZS1lZGl0aW9u">difference in books</a> with a ridiculous title. The difference between eight books and dozens can&#8217;t be explained away by Python being simpler, the Django docs being better, or Rails being more of a moving target (all true); none of them would stop publishers from trying to profit from an audience. The jobs, the searches, the books: they&#8217;re imprecise metrics that all point the same direction.
</p>

<p>
Rewind. Rails and Django were roughly technologically equivalent. They were both once a little flaky and incomplete and Definitely Didn&#8217;t Scale. But with the aid of good marketing, Rails turned its earlier release into a lead in in the developer market and created a vibrant, growing community (even if that community acts out a self-parody roughly annually).
</p>

<p>
Rails has had more resources in the form of bloggers, coders, writers, trainers, and users, and it&#8217;s used them to push in far more directions than Django has. Rails has explored dead ends like <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5ydWJ5LWZvcnVtLmNvbS90b3BpYy82Njg5Ng==">components</a>, built plugins and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Jsb2cuamF5ZmllbGRzLmNvbS8yMDA2LzEyL3JhaWxzLXBsdWdpbnMtd2h5Lmh0bWw=">changed course</a> to use <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3J5YW5kYWlnbGUuY29tL2FydGljbGVzLzIwMDgvNC8xL3doYXQtcy1uZXctaW4tZWRnZS1yYWlscy1nZW0tZGVwZW5kZW5jaWVz">better integration</a> with its package manager, and soon the entire Merb sort-of-fork project is <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3dlYmxvZy5ydWJ5b25yYWlscy5vcmcvMjAwOC8xMi8yMy9tZXJiLWdldHMtbWVyZ2VkLWludG8tcmFpbHMtMw==">merging</a> into Rails with the results of its successful experiments.
</p>

<p>
Django hasn&#8217;t moved nearly as fast, it hasn&#8217;t had the resources to make as many <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5lcmljc2luay5jb20vYm9zL01ha2VfTW9yZV9NaXN0YWtlcy5odG1s">mistakes</a> to learn from. The Django community is recovering from an 18 month gap between feature releases (<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kamFuZ29wcm9qZWN0LmNvbS93ZWJsb2cvMjAwNy9tYXIvMjMvMDk2Lw==">0.96</a> on March 23, 2007 and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kamFuZ29wcm9qZWN0LmNvbS93ZWJsb2cvMjAwOC9zZXAvMDMvMS8=">1.0</a> on September 3, 2008). 1.0 included a lot of great features and improvements, but it was a long, quiet year-and-half getting there while Rails was continuing to iterate.
</p>

<p>
It&#8217;s not a question comparing 1.0 minus .96 against 2.2 minus 1.2.3. It&#8217;s about activity and momentum, Django lost it while Rails has used the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9OZXR3b3JrIGVmZmVjdHM=">network effect</a> to grow the most active web development community to build better software. Count the amount of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Jsb2dzZWFyY2guZ29vZ2xlLmNvbS9ibG9nc2VhcmNoP2hsPWVuJiMwMzg7aWU9VVRGLTgmIzAzODtxPQ=="ruby+on+rails\"&#038;btnG=Search+Blogs\">blog posts</a>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5oYXNocm9ja2V0LmNvbS9wcm9kdWN0cw==">consultancies</a>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL251YnlvbnJhaWxzLmNvbS8=">newbies</a>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy56ZWRzaGF3LmNvbS9yYW50cy9yYWlsc19pc19hX2doZXR0by5odG1s">rants</a>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpdGh1Yi5jb20vcmFpbHMvcmFpbHMvY29tbWl0LzIyYWY2MmNmNDg2NzIxZWUyZTQ1YmI3MjBjNDJhYzJmNDEyMWZhZjQ=">silliness</a>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpdGh1Yi5jb20vc2VhcmNoP3E9cmFpbHM=">projects</a>, and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3dlYmxvZy5ydWJ5b25yYWlscy5vcmcvMjAwOS8xLzUvYW5ub3VuY2luZy10aGUtcmFpbHMtYWN0aXZpc3Rz">weaknesses addressed</a> instead of books and see how Rails has succeeded. It <em>is</em> its own ecosystem instead of only being part of the web.
</p>

<p>
The difference in relative success is that Django&#8217;s still a useful tool for building good websites. Meanwhile, Rails has Changed The Web, influencing <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy4zN3NpZ25hbHMuY29tL3N2bi9hcmNoaXZlcy8wMDA1NTgucGhw">graphic design</a>, pushing <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfMi4w">collaboration</a>, proving the value of Javascript <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5wcm90b3R5cGVqcy5vcmcv">toolkits</a>, driving the adoption of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpdC1zY20uY29tLw==">distributed version control</a>. I&#8217;m not claiming Rails is singlehandedly responsible for these trends, I&#8217;m saying it&#8217;s been a dominant force in these advancements of the web.
</p>

<p>
The Django and Rails communities fight so much and so rudely because they&#8217;re too similar not to. Projects survive and thrive because they have attention from developers, and developers don&#8217;t often pick up two tools to do the same job (usually it&#8217;s one tool for every job). Community is the lifeblood of every open source project and the world of difference between Django and Rails is evidence.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=554" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2009/open-source-communities/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Django vs Rails: The Dead-Tree Edition</title>
		<link>http://push.cx/2009/django-vs-rails-the-dead-tree-edition</link>
		<comments>http://push.cx/2009/django-vs-rails-the-dead-tree-edition#comments</comments>
		<pubDate>Sun, 18 Jan 2009 19:30:34 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[books]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://push.cx/?p=399</guid>
		<description><![CDATA[Django Rails In Conclusion The difference speaks for itself. I&#8217;ll write about why this matters tomorrow. (Yeah, I used the Fancy Link Builder I posted yesterday about. It was infuriating to use, it has whiz-bang Javascript to open a product detail lightbox that served only to make it nearly impossible to copy cover images. New [...]]]></description>
			<content:encoded><![CDATA[<h3>Django</h3>

<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzAxMzIzNTYxMzkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51y3VtGapML._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE0MzAyMTA0NzgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/516STCBRnOL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTcyNTcvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51TgEPuRPvL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE4NDcxOTMzNTgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51KV6GDQNRL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA2NzIzMjk1OVgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/21vjgVyKobL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE4NDcxOTU3MDkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41w-iUI3YXL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAxMzgwOTIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41TCjBvrSYL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE0MzAyMTkzODYvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51a7iRFovkL._SL160_.jpg"></a>

<h3>Rails</h3>

<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzAzMjE0NDU2MTkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51QMXWhhVjL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1MjkyNjAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51bobMnaN4L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA5ODA0NTUyMDAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51a9QwzgBoL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1MTU3NzQvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51gQ8Ol15gL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA5Nzc2MTY2MzAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51KxXNu8g3L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1MTUyMDAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51GwHSlh8BL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzAzMjE0OTA0NTIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51NG5mF-SAL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1MjczMTQvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/515UAKz4xpL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAwNjkxNTUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41BAq6RJ2VL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzQzNTYyMzkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51OLRygjI0L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzIzOTQ2OTkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41tTB2jdYCL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1MTg3NzMvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51sqo-%2BaCCL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAyNTgyMjUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/510G6HV9apL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA5Nzc2MTY2MDYvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51jCF6MuL3L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzAzMjE0ODA3OTEvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51W2gZ6rlnL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTYxMDEzMjUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51qbrSw4sGL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1Mjc0NDYvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51nQnMz4y2L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTY4NjIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/511nGo%2BS9-L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA5Nzg3MzkyMDUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51Gp324uWrL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzQzNTYxMjMvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51pFUUERPgL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTY1MTAzMjIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51bvVPHlpeL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTg0MTUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41zAqazU8zL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzQzNTYyMDQvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51cctS-JKgL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzM5ODg1MDkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51QysfVDlVL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTg0NzQvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41D2fWLxW2L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAwODEyMDEvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/5127VkAT6GL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwL0IwMDBQMjhXSk8vP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/414cCaAVrsL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAxODk0ODcvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41pAXWlJYYL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAyMjM4OFgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/416ucPUFGXL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTczNjIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41cHCApIIoL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTc4MTgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41ISDydfaTL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA5NzU4NDE5NTUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51QRVmc5-9L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA5Nzc2MTY2OVgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51k6buikSWL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE4NDcxOTM5ODYvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51guAgtKbfL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzQzNTYwNDIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41dR1eGL44L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzAzMjE1MTcwNjcvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41Kl2XX58SL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTc1MjQvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41m97RSl5vL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTA1OTkzMzAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41DJKGMk5vL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE4NDcxOTM0MTIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51KIECGkaQL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTY3MTM4MzYvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51M0pT6qBAL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE1OTY3MTMwODkvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41ZAr-k1jIL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzAxMzI0MTc5OTUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51%2B8ZrPMj6L._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MjE1NzMxMjAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51zXQUtOmoL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzM1NDA3MzE0NFgvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41FGiiVTI%2BL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA0NzAzNzQ5NTAvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41RFlrF8xLL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE4NDcxOTM5MzUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51nJbQqygPL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzM0NDY0MDkzMjcvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41DS37fvPuL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzA1OTYxMDE1MDMvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51wcYzxJGLL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE4NDcxOTA4NTUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51-ILxOshkL._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzM4OTg2NDQwMjIvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/41WzCwSl4ML._SL160_.jpg"></a>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5hbWF6b24uY29tL2RwLzE5MzIzOTQ3NDUvP3RhZz1wdXNoY3gtMjA="><img border="0" src="/wp-content/uploads/2009/01/51U3TcTocZL._SL160_.jpg"></a>

<h3>In Conclusion</h3>
<p>
The difference speaks for itself. I&#8217;ll write about why this matters <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDkvb3Blbi1zb3VyY2UtY29tbXVuaXRpZXM=">tomorrow</a>.
</p>

<p class="aside">
(Yeah, I used the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDkvdHdvLWludGVyYWN0aW9ucy13aXRoLWFtYXpvbg==">Fancy Link Builder</a> I posted yesterday about. It was infuriating to use, it has whiz-bang Javascript to open a product detail lightbox that served only to make it nearly impossible to copy cover images. New theory: the creators of the Fancy Link Builder are moles from offline bookstores who have infiltrated Amazon to destroy it from within.)
</p>

 <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=399" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2009/django-vs-rails-the-dead-tree-edition/feed</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>RailsRumble Postmortem</title>
		<link>http://push.cx/2008/railsrumble-postmortem</link>
		<comments>http://push.cx/2008/railsrumble-postmortem#comments</comments>
		<pubDate>Sun, 19 Oct 2008 23:28:38 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[AASM]]></category>
		<category><![CDATA[Bort]]></category>
		<category><![CDATA[ConfReader]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[haml]]></category>
		<category><![CDATA[open_id_authentication]]></category>
		<category><![CDATA[Paperclip]]></category>
		<category><![CDATA[planning]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[RailsRumble]]></category>
		<category><![CDATA[resource_this]]></category>
		<category><![CDATA[restful_authentication]]></category>
		<category><![CDATA[RSpec]]></category>
		<category><![CDATA[scheduling]]></category>
		<category><![CDATA[teamwork]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/?p=364</guid>
		<description><![CDATA[I failed to launch my Rails Rumble project ConfReader. Why? Poor scheduling Couldn&#8217;t stay up because work is demanding in the election season, so working late would mean I&#8217;d limp through the next week of important coverage. More than that, though, was a bad mistake in scheduling a social outing. I didn&#8217;t figure in some [...]]]></description>
			<content:encoded><![CDATA[<p>
I failed to launch my Rails Rumble project <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDgvcmFpbHNydW1ibGluZw==">ConfReader</a>. Why?
</p>


<h3>Poor scheduling</h3>
<p>
Couldn&#8217;t stay up because work is demanding in the election season, so working late would mean I&#8217;d limp through the next week of important coverage. More than that, though, was a bad mistake in scheduling a social outing. I didn&#8217;t figure in some of travel time and the friend driving wanted to spend a lot more time out, so instead of having a nice morning out I got home at 7 PM tired and in a foul mood. I was able to relax a bit and get some code done, but it cut my available time by more than half.
</p>


<h3>Too many new toys</h3>
<p>
I knew I hadn&#8217;t played with encoding video before, so I asked an expert for some tips and tinkered around breaking test videos down into short, easily-transcribed segments. Not coincidentally, this is basically the only feature that works. I started with <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpdGh1Yi5jb20vZnVkZ2VzdHVkaW9zL2JvcnQvdHJlZS9tYXN0ZXI=">bort</a> to get a lot of basic functionality quickly, but I had no experience with most of the plugins it provided (and those I otherwise planned to use).
</p>

<dl>
  <dt>aasm</dt> <dd>Differences between acts_as_state_machine (which I started with) and aasm (the successor that bort ships).</dd>
  <dt>haml</dt> <dd>Translating scaffolding from erb to haml and a (still-unsolved) bug that causes it to render content twice on one page. (And I&#8217;ve even used haml before.)</dd>
  <dt>open_id_authentication/restful_authentication</dt> <dd>I wanted users to be able to contribute anonymously or use OpenID to receive credit for their contributions without having to set up an account, and the plugins came configured for conventional user accounts.</dd>
  <dt>resource_this</dt> <dd>I had to fix a templating bug, and there&#8217;s a fair amount of magic to learn to work with.</dd>
  <dt>rspec</dt> <dd>Scaffolded tests needed slow, tedious tweaks to work with resource_this. I think I like the idea of rspec more than the implementation.</dd>
  <dt>paperclip</dt> <dd>Sorting out finicky path/url issues, and I couldn&#8217;t find a way to mock validates_attachment_presence so several models went unspeced..</dd>
</dl>

<p>
Each of these issues ate 30-60m, and there went the time to build. Some plugins (acts_as_versioned, footnotes, random_finders) just worked great, but none was really related to core functionality. Speaking of which:
</p>


<h3>Core featureset too big</h3>
<p>
The line between nothing and application includes site graphic design, listing conferences, uploading presentation videos, splitting videos into segments, adding transcripts, viewing all of the these, editing transcripts&#8230; I had a lot of features listed as optional, but there was still a long set of base features and each uncovered another one of those frustrations.
</p>


<h3>No teammates</h3>
<p>
It would&#8217;ve helped a lot to have someone to work with. Not just because it would have taken less time to finish the core features, but for the enjoyment of teamwork and to complement my weaknesses.
</p>

<h3>All told</h3>
<p>
I&#8217;m glad I spent time I spent hanging out in #railsrumble or on the RailsRumble present.ly. Even if it didn&#8217;t directly result in items checked off the todo list, it&#8217;s been a fun community to be in, and I was glad to help folks out. I&#8217;m eager to see what other people came up with.
</p>

<p>
I didn&#8217;t enter RailsRumble to win, I entered for the excuse to create what I thought was an interesting small project. I&#8217;ll pick ConfReader back up in a little while, probably after the election. I still think it&#8217;s too good an idea not to build, but I&#8217;m a bit tired right now.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=364" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2008/railsrumble-postmortem/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>RailsRumbling</title>
		<link>http://push.cx/2008/railsrumbling</link>
		<comments>http://push.cx/2008/railsrumbling#comments</comments>
		<pubDate>Thu, 16 Oct 2008 13:01:35 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[crunch]]></category>
		<category><![CDATA[experiment]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[RailsRumble]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/?p=356</guid>
		<description><![CDATA[I&#8217;m participating in RailsRumble this weekend, from 8 PM Friday to 8 PM Sunday. The goal is to build a web application in Ruby on Rails in 48 hours, and I welcome the change of pace of a small project. It&#8217;ll be a fun weekend crunch to build it, and I hope it will be [...]]]></description>
			<content:encoded><![CDATA[ <p>
I&#8217;m participating in <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3JhaWxzcnVtYmxlLmNvbS8=">RailsRumble</a> this weekend, from 8 PM Friday to 8 PM Sunday. The goal is to build a web application in Ruby on Rails in 48 hours, and I welcome the change of pace of a small project. It&#8217;ll be a fun weekend crunch to build it, and I hope it will be a long-term resource for the development community.
</p>

<p>
I&#8217;ve watched a lot of video from conferences in the last month or two, and they really frustrated me. Video is slow and linear &#8212; I could read five presentations instead of watching one and wondering if it&#8217;s going to be worth the time it takes. I really appreciate all the presentations, I just get impatient trying to find out if I&#8217;m going to enjoy one, or waiting for the speaker to make their next interesting point. And it&#8217;s hard to share them &#8212; &#8220;Hey, skim this web page&#8221; is a lot easier than &#8220;Hey, commit to watching this hour&#8221;.
</p>

<p>
My app is going make it easy for folks to collaboratively transcribe presentations so anyone can read them alongside the slides. It&#8217;ll break up video into short pieces so people can help transcribe in a few minutes&#8217; spare time rather than a big hours-long investment. If the presenter has put their slides online, they&#8217;ll be integrated with the text. If you&#8217;re a expert with Flash video and want to join in, I could use a hand &#8212; otherwise, that part of the app will probably just be very plain, a video with a timeline control at the bottom rather than something specialized for transcription.
</p>

<p>
If this sounds like a useful site, I&#8217;d really appreciate a few minutes of your help late Saturday or early Sunday. Teams can only be 4 people, but I got the OK to allow the public to work on content on the site during the contest so it doesn&#8217;t have to launch empty. Just watch this blog (or mail me if you&#8217;d like me to remind you) this weekend for the call to come start using the site. Even a few minutes would be a big help.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=356" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2008/railsrumbling/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Rails URL Params as Types</title>
		<link>http://push.cx/2008/rails-url-params-as-types</link>
		<comments>http://push.cx/2008/rails-url-params-as-types#comments</comments>
		<pubDate>Tue, 26 Aug 2008 22:36:43 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[strings]]></category>
		<category><![CDATA[typing]]></category>
		<category><![CDATA[URLs]]></category>

		<guid isPermaLink="false">http://push.cx/?p=314</guid>
		<description><![CDATA[Yesterday I (belatedly) took my friend Nola Stowe&#8216;s advice and picked up a book she tech-reviewed, The Rails Way by Obie Fernandez. It&#8217;s been a great read so far (about 85 pages in), and I just realized that routing is largely about type conversion. In the explanation of named routes, there&#8217;s a series of examples [...]]]></description>
			<content:encoded><![CDATA[<p>
Yesterday I (belatedly) took my friend <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3J1YnlnZWVrLmNvbS8=">Nola Stowe</a>&#8216;s advice and picked up a book she tech-reviewed, The Rails Way by Obie Fernandez. It&#8217;s been a great read so far (about 85 pages in), and I just realized that routing is largely about type conversion.
</p>

<p>
In the explanation of named routes, there&#8217;s a series of examples demonstrating the increasing amounts of syntactic sugar Rails provides:
</p>

<pre>&nbsp;
<span style="color: #808080; font-style: italic;"># The most explicit way, before you define the named route:</span>
&lt;%= link_to <span style="color: #ff0000;">"Auction for #{h(auction.item.description)}"</span>,
    :controller =&gt; <span style="color: #ff0000;">"auctions"</span>,
    :action     =&gt; <span style="color: #ff0000;">"show"</span>,
    :id         =&gt; auction.<span style="">id</span> %&gt;
&nbsp;
<span style="color: #808080; font-style: italic;"># The first use of the named route, no need to specify controller or action:</span>
&lt;%= link_to <span style="color: #ff0000;">"Auction for #{h(auction.item.description)}"</span>, auction_path<span style="color: #66cc66;">&#40;</span>:id =&gt; auction.<span style="">id</span><span style="color: #66cc66;">&#41;</span> %&gt;
&nbsp;
<span style="color: #808080; font-style: italic;"># If you just have an :id argument to fill in, you can just pass the value:</span>
&lt;%= link_to <span style="color: #ff0000;">"Auction for #{h(auction.item.description)}"</span>, auction_path<span style="color: #66cc66;">&#40;</span>auction.<span style="">id</span><span style="color: #66cc66;">&#41;</span> %&gt;
&nbsp;
<span style="color: #808080; font-style: italic;"># And you could just pass the object and Rails will get its id:</span>
&lt;%= link_to <span style="color: #ff0000;">"Auction for #{h(auction.item.description)}"</span>, auction_path<span style="color: #66cc66;">&#40;</span>auction<span style="color: #66cc66;">&#41;</span> %&gt;</pre>

<p>
In Rails it&#8217;s just syntactic sugar, but the underlying mechanism here is type coercion. Instead of thinking of a URL having the type &#8216;string&#8217;, think of it having the type &#8216;URL&#8217;. (Here&#8217;s where all the Haskell guys are saying &#8220;Uh, it does already.&#8221; and rolling their eyes. You already get it, so this post is not for you.) The syntactic sugar is quietly converting an <kbd>auction</kbd> object into a <kbd>url</kbd> object (or part of one, really).
</p>

<p>
In Rails you can define a <kbd>to_param</kbd> method on your object that&#8217;s called by <kbd>url_for</kbd> (the method underlying <kbd>link_to</kbd>), and the name gives away that you&#8217;re converting type like the <kbd>to_i</kbd>, <kbd>to_s</kbd>, <kbd>to_f</kbd> methods you already know from Ruby&#8217;s builtin types.
</p>

<p>
The reverse is less seamless. There is no <kbd>Model.from_param</kbd>. Rails&#8217; routing unpacks the URL into variables for the code you write in your controller to find the object(s). In a RESTful style, it seems odd that Rails doesn&#8217;t default to doing something like <kbd>@<i>model_name</i> = <i>Model</i>.find(params[:id])</kbd> if you don&#8217;t define your own <kbd>load_object</kbd> <kbd>before_filter</kbd>.
</p>

<p>
I&#8217;ve been thinking a lot about <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SZXByZXNlbnRhdGlvbmFsX1N0YXRlX1RyYW5zZmVy">REST</a> lately. The URL of a resource is that resource converted to a URL type. A view presenting an object could be considered converting it to an HTML type. Controllers and actions&#8230; I can&#8217;t quite see putting them into my models, but they seem much less distinct to me than they did a few hours ago.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=314" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2008/rails-url-params-as-types/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Painless Upgrade to Rails 2.0</title>
		<link>http://push.cx/2007/painless-upgrade-to-rails-20</link>
		<comments>http://push.cx/2007/painless-upgrade-to-rails-20#comments</comments>
		<pubDate>Thu, 13 Dec 2007 12:10:20 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[ActiveResource]]></category>
		<category><![CDATA[NearbyGamers]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Rails 2.0]]></category>
		<category><![CDATA[routing]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[tests]]></category>
		<category><![CDATA[upgrade]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2007/painless-upgrade-to-rails-20</guid>
		<description><![CDATA[I spent a dead-easy 2.5 hours last night updating NearbyGamers to Rails 2.0. My svn commit message read (with links added here for convenience): Updated to Rails 2.0.1 rm&#8217;d lib/slash_urls.rb: Rails switched from ; to / to separate actions rm&#8217;d lib/resource_requirements.rb: now included in ActiveResources rm&#8217;d app/helpers/tags_helper.rb and gamers_helper.rb that had old controller names and [...]]]></description>
			<content:encoded><![CDATA[<p>
I spent a dead-easy 2.5 hours last night updating <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20=">NearbyGamers</a> to Rails 2.0. My svn commit message read (with links added here for convenience):
</p>

<blockquote>
Updated to Rails 2.0.1

<ul>
<li>rm&#8217;d <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNy9yYWlscy1zZW1pY29sb25zLW91dC1zbGFzaGVzLWlu">lib/slash_urls.rb</a>: Rails switched from ; to / to separate actions</li>
<li>rm&#8217;d <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Rldi5ydWJ5b25yYWlscy5vcmcvdGlja2V0Lzc2MzMgd2l0aA0KCmh0dHA6Ly9wdXNoLmN4LzIwMDcvcmFpbHMtc2VtaWNvbG9ucy1vdXQtc2xhc2hlcy1pbgoK">lib/resource_requirements.rb</a>: now included in ActiveResources</li>
<li>rm&#8217;d app/helpers/tags_helper.rb and gamers_helper.rb that had old controller names and were unused anyways</li>
<li>app/controllers/gamers_controller.rb: documented and fixed raw post variable extraction</li><li>updated post_path linkers in many views, controllers, and tests</li>
<li>renamed discussion_anchor_post_path to anchor_discussion_post_path to match the new ordering for nested resource urls</li>
<li>fix tag sorting on <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20vdGFncw==">tag index</a></li>
<li>move tags from /tags/Board+Games to <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20vdGFncy9Cb2FyZF9HYW1lcw==">/tags/Board_Games</a>, as Rails fixed the bug that encoded &#8216; &#8216; as &#8216;+&#8217; in non-get variable parts of the URL</li>
</ul>
</blockquote>

<h2>The Details</h2>

<p>
The first two files I deleted were my patches to URL generation that Rails now includes. The next two helper files I never used, but had had old (singular noun) names.
</p>

<p>
The bit about documentation: the way to get at raw post variables changed, so I tweaked code and left myself a reminder of why I&#8217;m doing it (I had to look at the changelog, which means it wasn&#8217;t self-evident).
</p>

<p>
Nested resources (I have nested <kbd>map.resources :discussions { |d| d.resources :posts }</kbd>) changed from <kbd>discussion_edit_post_url</kbd> to <kbd>edit_discussion_post_url</kbd>, so there was a bunch of places to change that. The next change about anchor is me following this convention with my own convenience method.
</p>

<p>
Tag sorting on the index page was a bug that Snarky pointed out to me. When I made some performance tweaks to that page I forgot to keep sorting tags as they came out of the database. This arguably should&#8217;ve been a revision of its own as it&#8217;s unrelated to the upgrade, but it was an easy one-line bugfix so I let it in.
</p>

<p>
Last, I renamed the tag pages. The tag model&#8217;s <kbd>to_param</kbd> just returns <kbd>self.name</kbd> and Rails would turn &#8220;Board Games&#8221; into &#8220;Board+Games&#8221;. It&#8217;s common but technically incorrect, as + only means space in encoded GET/POST variables. The proper encoding of &#8220;Board%20Games&#8221; was really noisy, so I took a page from Wikipedia&#8217;s pagebook and use underscores instead, like &#8220;Board_Games&#8221;. Was one line in the <kbd>to_param</kbd> and one line in the controller&#8217;s <kbd>load_tag</kbd> before_filter, a dozen lines of tweaking old tests, and seven lines of new tests. Eeeeeasy. 
</p>

<h2>The Verdict</h2>

<p>
Tests, tests, tests. If I didn&#8217;t have a solid test suite, I&#8217;d be noticing bugs two months from now in the least-frequently-exercised bits of code. Not only would I not have remembered to test some of the functionality, I wouldn&#8217;t have remembered the corner cases &#8212; or maybe I&#8217;d just have gotten bored of clicking through pages over and over and ignored the corner cases.
</p>

<p>
None of these were hard fixes and none were frustrating. I&#8217;d probably have finished even sooner if I hadn&#8217;t also been poking <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2ljYW5oYXNjaGVlemJ1cmdlci5jb20vMjAwNy8xMi8xMS9taXRvc2lzLw==">lolcats</a> and chatting with friends. And now I have a big list of shiny new Rails 2.0 features I can put to work in <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20=">NearbyGamers</a>.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=292" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/painless-upgrade-to-rails-20/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Logging Internal Server Errors</title>
		<link>http://push.cx/2007/logging-internal-server-errors</link>
		<comments>http://push.cx/2007/logging-internal-server-errors#comments</comments>
		<pubDate>Fri, 27 Apr 2007 21:40:12 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[500 errors]]></category>
		<category><![CDATA[error handling]]></category>
		<category><![CDATA[errors]]></category>
		<category><![CDATA[internal server errors]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[rescue]]></category>

		<guid isPermaLink="false">http://push.cx/2007/logging-internal-server-errors</guid>
		<description><![CDATA[A good rule of thumb for websites is that for every hundred users who runs into a bug, one will let you know. This is when the user can even recognize there&#8217;s an error because they get a big &#8220;500: Internal Server Error&#8221;. You might get more reports if you have a very small userbase [...]]]></description>
			<content:encoded><![CDATA[<p>
A good rule of thumb for websites is that for every hundred users who runs into a bug, one will let you know. This is when the user can even recognize there&#8217;s an error because they get a big &#8220;500: Internal Server Error&#8221;. You might get more reports if you have a very small userbase who know you, but don&#8217;t count on it. You have to log errors if you want to find out about them, so here&#8217;s some code to do that in Rails.
</p>

<p>
By default Rails logs all accesses and errors to production.log, but I decided to save errors to individual files to save the hassle of trying to sift them out of that haystack. I considered logging them to a database table, mailing them, or providing an RSS feed but in the end decided to punt on it. Every added bit of complexity in <kbd>rescue_error_in_public</kbd> is another opportunity for something else to go wrong and the error to be lost. It&#8217;s easy to write a cron job or other service to pick them up from files and do something useful with them.
</p>

<p>
Save this file as <kbd>lib/handle_errors.rb</kbd>:
</p>
<pre>&nbsp;
module ActionController
module Rescue
  def rescue_action_in_public<span style="color: #66cc66;">&#40;</span>exception<span style="color: #66cc66;">&#41;</span>
    <span style="color: #b1b100;">case</span> exception
      when ::<span style="color: #006600;">ActionController</span>::<span style="color: #006600;">RoutingError</span>, ::<span style="color: #006600;">ActionController</span>::<span style="color: #006600;">UnknownAction</span>
        render_text<span style="color: #66cc66;">&#40;</span>IO.<span style="">read</span><span style="color: #66cc66;">&#40;</span>File.<span style="">join</span><span style="color: #66cc66;">&#40;</span>RAILS_ROOT, <span style="color: #ff0000;">'public'</span>, <span style="color: #ff0000;">'404.html'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">"404 Not Found"</span><span style="color: #66cc66;">&#41;</span>
      <span style="color: #b1b100;">else</span>
        render_text<span style="color: #66cc66;">&#40;</span>IO.<span style="">read</span><span style="color: #66cc66;">&#40;</span>File.<span style="">join</span><span style="color: #66cc66;">&#40;</span>RAILS_ROOT, <span style="color: #ff0000;">'public'</span>, <span style="color: #ff0000;">'500.html'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">"500 Internal Error"</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #000066;">defined</span>? ERROR_PATH
          File.<span style="">open</span><span style="color: #66cc66;">&#40;</span>File.<span style="">join</span><span style="color: #66cc66;">&#40;</span>ERROR_PATH, Time.<span style="">now</span>.<span style="">strftime</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"exception_%Y-%m-%d_%H:%M:%S_#{rand(99999)}"</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">'w'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">do</span> |file|
            try_printing<span style="color: #66cc66;">&#40;</span>file, <span style="color: #ff0000;">"request"</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> file.<span style="">print</span> <span style="color: #ff0000;">"Request to #{request.request_uri} from #{request.remote_ip}nn"</span> <span style="color: #66cc66;">&#125;</span>
            try_printing<span style="color: #66cc66;">&#40;</span>file, <span style="color: #ff0000;">"params"</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> file.<span style="">print</span> <span style="color: #ff0000;">"Params #{params.to_yaml}nn"</span> <span style="color: #66cc66;">&#125;</span>
            try_printing<span style="color: #66cc66;">&#40;</span>file, <span style="color: #ff0000;">"exception"</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> file.<span style="">print</span><span style="color: #66cc66;">&#40;</span>
              <span style="color: #ff0000;">"#{exception.class} (#{exception.message}):n    "</span> +
              clean_backtrace<span style="color: #66cc66;">&#40;</span>exception<span style="color: #66cc66;">&#41;</span>.<span style="">join</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"n    "</span><span style="color: #66cc66;">&#41;</span> +
              <span style="color: #ff0000;">"nn"</span>
            <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#125;</span>
            try_printing<span style="color: #66cc66;">&#40;</span>file, <span style="color: #ff0000;">"session"</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> file.<span style="">print</span> <span style="color: #ff0000;">"Session #{session.to_yaml}nn"</span> <span style="color: #66cc66;">&#125;</span>
          <span style="color: #b1b100;">end</span>
        <span style="color: #b1b100;">end</span>
    <span style="color: #b1b100;">end</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#  def rescue_action_locally(exception)</span>
<span style="color: #808080; font-style: italic;">#    rescue_action_in_public(exception)</span>
<span style="color: #808080; font-style: italic;">#  end</span>
&nbsp;
  def try_printing file, title
    begin
      yield
    rescue Exception =&gt; exception
      file.<span style="">print</span> <span style="color: #ff0000;">"Failed to print #{title}: #{exception.class} (#{exception.message})nn"</span>
    <span style="color: #b1b100;">end</span>
  <span style="color: #b1b100;">end</span>
end
<span style="color: #b1b100;">end</span></pre>

<p>
Edit your <kbd>config/environments.rb<kbd> to <strong><kbd>require 'handle_errors'</kbd></strong> and, in your specific <kbd>config/environment</kbd> files, add <strong><kbd>ERROR_PATH = '/path/to/save'</kbd></strong>. You can see this working in development by uncommenting the <kbd>rescue_action_locally</kbd>.
</p>

<p>
Security note: If you're dealing with credit cards or other sensitive financial or personal data, you'll want to scrub that from <kbd>params</kbd> and <kbd>session</kbd> before logging.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=235" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/logging-internal-server-errors/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Discussion URLs: Opaque, Usable, and Readable</title>
		<link>http://push.cx/2007/discussion-urls-opaque-usable-and-readable</link>
		<comments>http://push.cx/2007/discussion-urls-opaque-usable-and-readable#comments</comments>
		<pubDate>Thu, 05 Apr 2007 13:03:30 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[ActiveResource]]></category>
		<category><![CDATA[human-readable]]></category>
		<category><![CDATA[named routes]]></category>
		<category><![CDATA[nested routes]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[resources]]></category>
		<category><![CDATA[RESTful]]></category>
		<category><![CDATA[routes]]></category>
		<category><![CDATA[routing]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[URLs]]></category>

		<guid isPermaLink="false">http://push.cx/2007/discussion-urls-opaque-usable-and-readable</guid>
		<description><![CDATA[I just wrote about Human-Readable ActiveResource URLs, and now I want to examine one example of them more in-depth. Discussion forum URLs have several conflicting goals: human-readable I should get some idea of what the discussion&#8217;s about when I hover over a link permanent bookmarks, incoming links, and search engines all need reliable URLs editable [...]]]></description>
			<content:encoded><![CDATA[<p>
I just wrote about <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNy9odW1hbi1yZWFkYWJsZS1hY3RpdmVyZXNvdXJjZS11cmxz">Human-Readable ActiveResource URLs</a>, and now I want to examine one example of them more in-depth. Discussion forum URLs have several conflicting goals:
</p>

<dl>
  <dt>human-readable</dt> <dd>I should get some idea of what the discussion&#8217;s about when I hover over a link</dd>
  <dt>permanent</dt> <dd>bookmarks, incoming links, and search engines all need reliable URLs</dd>
  <dt>editable</dt> <dd>If a discussion drifts, it needs a new subject, which means it needs a new URL</dd>
  <dt>opaque</dt> <dd>I&#8217;d rather not roll out the carpet for someone to scrape all the discussions</dd>
</dl>

<p>
After a bit of pondering, I decided that URLs should look like this:
</p>

<p>
http://nearbygamers.com/discussions/<b>{slug}</b>-<b>{post count}</b>-<b>{subject}</b>
</p>

<dl>
  <dt>slug</dt> <dd>An unchanging random 5-character string.</dd>
  <dt>post count</dt> <dd>The number of posts in this discussion, so that when you look at the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJ5YmdhbWVycy5jb20vZGlzY3Vzc2lvbnM=">discussions index</a> you know at a glance if you&#8217;ve read a thread because your browser colors visited links. I snagged this off <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5qb2Vsb25zb2Z0d2FyZS5jb20vYXJ0aWNsZXMvQnVpbGRpbmdDb21tdW5pdGllc3dpdGhTby5odG1s">the Joel</a>.</dd>
  <dt>subject</dt> <dd>Just the alphanumerics, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5tYXR0Y3V0dHMuY29tL2Jsb2cvZGFzaGVzLXZzLXVuZGVyc2NvcmVzLw==">dash-separated</a>, updated as the subject is edited</dd>
</dl>

<p>
So two parts (post count and subject) on a discussion can change, and the controller uses the slug to load the discussion and redirect to the correct URL if either has changed. Bookmarks and search engines can update, and outside links never stop working.
</p>

<h3>The Code</h3>

<p>
First, a little snippet of code to generate slugs lives in <kbd>lib/slug.rb</kbd>:
</p>

<pre>&nbsp;
def random_slug<span style="color: #66cc66;">&#40;</span><span style="color: #000066;">length</span>=<span style="color: #cc66cc;">5</span><span style="color: #66cc66;">&#41;</span>
  chars = <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"a"</span>..<span style="color: #ff0000;">"z"</span><span style="color: #66cc66;">&#41;</span>.<span style="">to_a</span> + <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"A"</span>..<span style="color: #ff0000;">"Z"</span><span style="color: #66cc66;">&#41;</span>.<span style="">to_a</span> + <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"1"</span>..<span style="color: #ff0000;">"9"</span><span style="color: #66cc66;">&#41;</span>.<span style="">to_a</span>
  Array.<span style="">new</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066;">length</span>, <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span>.<span style="">collect</span><span style="color: #66cc66;">&#123;</span>chars<span style="color: #66cc66;">&#91;</span><span style="color: #000066;">rand</span><span style="color: #66cc66;">&#40;</span>chars.<span style="">size</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#125;</span>.<span style="">join</span>
<span style="color: #b1b100;">end</span></pre>

<p>
The Discussion model uses this to set a slug on itself if it doesn&#8217;t have one yet, and then uses that slug to generate URLs (note that I remove multiple and leading/trailing hyphens from the subjects):
</p>

<pre>&nbsp;
<span style="color: #000066;">require</span> <span style="color: #ff0000;">'slug'</span>
&nbsp;
class Discussion &lt; ActiveRecord::<span style="color: #006600;">Base</span>
  def to_param
    <span style="color: #ff0000;">"#{slug}-#{posts.count}-#{subject.gsub(/[^[:alnum:]]+/i, '-').gsub(/-+/, '-').gsub(/^-|-$/, '')}"</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  protected
  def before_validation
    <span style="color: #b1b100;">if</span> self.<span style="">slug</span>.<span style="">empty</span>?
      begin
        self.<span style="">slug</span> = random_slug
      <span style="color: #b1b100;">end</span> <span style="color: #b1b100;">while</span><span style="color: #66cc66;">&#40;</span>Discussion.<span style="">count</span><span style="color: #66cc66;">&#40;</span>:conditions =&gt; <span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'slug = ?'</span>, self.<span style="">slug</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> &gt; <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #b1b100;">end</span>
  <span style="color: #b1b100;">end</span>
end</pre>

<p>
Finally, the DiscussionsController loads discussion objects, throws 404 errors, and redirects appropriately:
</p>

<pre>&nbsp;
class DiscussionsController &lt; ApplicationController
  before_filter :load_discussion, :except =&gt; <span style="color: #66cc66;">&#91;</span> :<span style="color: #000066;">index</span> <span style="color: #66cc66;">&#93;</span>
&nbsp;
  private
  def load_discussion
    slug = params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>.<span style="">split</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'-'</span><span style="color: #66cc66;">&#41;</span>.<span style="">first</span> <span style="color: #b1b100;">if</span> params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>
    <span style="color: #0000ff;">@discussion</span> = Discussion.<span style="">find_by_slug</span><span style="color: #66cc66;">&#40;</span>slug<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">if</span> slug
    raise ::<span style="color: #006600;">ActionController</span>::<span style="color: #006600;">RoutingError</span>, <span style="color: #ff0000;">"Recognition failed for #{request.path}"</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">@discussion</span>.<span style="">nil</span>?
    redirect_to discussion_path<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@discussion</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">and</span> <span style="color: #000066;">return</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">@discussion</span>.<span style="">to_param</span> != params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>
  <span style="color: #b1b100;">end</span></pre> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=233" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/discussion-urls-opaque-usable-and-readable/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Human-Readable ActiveResource URLs</title>
		<link>http://push.cx/2007/human-readable-activeresource-urls</link>
		<comments>http://push.cx/2007/human-readable-activeresource-urls#comments</comments>
		<pubDate>Tue, 03 Apr 2007 21:15:07 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[ActiveResource]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[human-readable]]></category>
		<category><![CDATA[named routes]]></category>
		<category><![CDATA[nested routes]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Rails 1.1]]></category>
		<category><![CDATA[Rails 1.2]]></category>
		<category><![CDATA[RESTful]]></category>
		<category><![CDATA[routes]]></category>
		<category><![CDATA[URLs]]></category>

		<guid isPermaLink="false">http://push.cx/2007/human-readable-activeresource-urls</guid>
		<description><![CDATA[I&#8217;ve got URLs on the brain this week. I started NearbyGamers using Rails 1.1 with just gamers and tags. I upgraded to Rails 1.2 (and liked it) , and added discussions after I updated to Rails 1.2. I was able to use ActiveResource for Discussions with Posts as a nested resource. I&#8217;m really happy with [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;ve got URLs on the brain this week. I started <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20=">NearbyGamers</a> using Rails 1.1 with just gamers and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vdGFncw==">tags</a>. I upgraded to Rails 1.2 (and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNy9yYWlscy0xMjEtaW1wcmVzc2lvbg==">liked it</a>)
, and added <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vZGlzY3Vzc2lvbnM=">discussions</a> after I updated to Rails 1.2. I was able to use ActiveResource for Discussions with Posts as a nested resource. I&#8217;m really happy with this code, as it&#8217;s very tidy.
</p>

<p>
On Sunday I updated gamers and tags to use ActiveResource. It wasn&#8217;t hard, mostly just renames (the &#8216;view&#8217; action became &#8216;show&#8217;, for example) and removing url_for hashes (<kbd>:controller => 'gamers', :action => 'view', :handle => @gamer.handle</kbd>) with much nicer named routes (<kbd>gamer_path(@gamer)</kbd>). A gripe I have about ActiveResource is that it has poor URLs, with internal record IDs leaking out. I&#8217;ve had nice URLs (<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vZ2FtZXJzL0hhcmtpbnM=">/gamers/Harkins</a> and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vdGFncy9SUEdz">/tags/RPGs</a>) for gamers and tags and I wanted to keep them.
</p>

<p>
Joshua Schacter gave a presentation on building and growing <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2RlbC5pY2lvLnVz">del.icio.us</a> that included the gems (among <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3NpbW9uLmluY3V0aW8uY29tL25vdGVzLzIwMDYvc3VtbWl0L3NjaGFjaHRlci50eHQ=">many other gems</a>):
</p>

<blockquote>
<ul>
  <li>Dont expose your unique id&#8217;s to the outside world (php?id=1 etc.) people can
scrape through everything very easily. This is why del.icio.us uses MD5 hashes
of links instead.
</li>
  <li>URLs are prime real estate &#8211; respect them</li>
</ul>
</blockquote>

<p>
It turns out this is not just possible but easy, though I blew an hour or so finding it (Rails docs still need love). In my Gamer and Tag objects, I just define a <kbd>to_param</kbd> method and the URL builder picks it up:
</p>

<pre>&nbsp;
class Gamer &lt; ActiveRecord::<span style="color: #006600;">Base</span>
  def to_param
    self.<span style="">handle</span>
  <span style="color: #b1b100;">end</span>
end
class Tag &lt; ActiveRecord::<span style="color: #006600;">Base</span>
  def to_param
    self.<span style="">name</span>
  <span style="color: #b1b100;">end</span>
end
&nbsp;
<span style="color: #808080; font-style: italic;"># and over in config/routes.rb I do the usual:</span>
<span style="color: #000066;">map</span>.<span style="">resources</span> :gamers
<span style="color: #000066;">map</span>.<span style="">resources</span> :tags, :memger =&gt; <span style="color: #66cc66;">&#123;</span> :history =&gt; :get, :variantes =&gt; :get <span style="color: #66cc66;">&#125;</span>
<span style="color: #808080; font-style: italic;"># and now gamer_path(@gamer) and tag_path(@tag) work in my views</span></pre>

<p>
My controller looks like:
</p>

<pre>&nbsp;
class GamersController &lt; ApplicationController
  before_filter :load_gamer, :except =&gt; <span style="color: #66cc66;">&#91;</span> :<span style="color: #000066;">index</span> <span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #808080; font-style: italic;"># The regular index, show, edit, and update actions here</span>
&nbsp;
  private
  def load_gamer
    <span style="color: #0000ff;">@gamer</span> = Gamer.<span style="">find_by_handle</span><span style="color: #66cc66;">&#40;</span>params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>, :include =&gt; <span style="color: #66cc66;">&#91;</span>:location, :tags<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>
    raise ::<span style="color: #006600;">ActionController</span>::<span style="color: #006600;">RoutingError</span>, <span style="color: #ff0000;">"Recognition failed for #{request.path}"</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">@gamer</span>.<span style="">nil</span>?
    <span style="color: #808080; font-style: italic;"># canonicalize case</span>
    redirect_to gamer_path<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@gamer</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">and</span> <span style="color: #000066;">return</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">@gamer</span>.<span style="">handle</span> != params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>
  <span style="color: #b1b100;">end</span></pre>

<p>
And every action that needs it has the @gamer object loaded from the URL param, with 404 errors handled and mistaken case fixed. There&#8217;s <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Rldi5ydWJ5b25yYWlscy5vcmcvdGlja2V0LzY4MTQ=">a patch</a> that will let you rename the :id parameter. I can&#8217;t say I mind if it&#8217;s not accepted; I don&#8217;t mind calling it :id instead of :handle or :name because I think of it as the public id of the object.
</p>

<p>
Come back Thursday, I&#8217;ll tell you how I made my discussion URLs even more useful.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=232" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/human-readable-activeresource-urls/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Rails: Semicolons Out, Slashes In</title>
		<link>http://push.cx/2007/rails-semicolons-out-slashes-in</link>
		<comments>http://push.cx/2007/rails-semicolons-out-slashes-in#comments</comments>
		<pubDate>Sun, 01 Apr 2007 21:50:23 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[map]]></category>
		<category><![CDATA[mapping]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[resources]]></category>
		<category><![CDATA[routes]]></category>
		<category><![CDATA[routing]]></category>
		<category><![CDATA[semicolon]]></category>
		<category><![CDATA[slash]]></category>
		<category><![CDATA[slashes]]></category>
		<category><![CDATA[URLs]]></category>

		<guid isPermaLink="false">http://push.cx/2007/rails-semicolons-out-slashes-in</guid>
		<description><![CDATA[As of r6485, Edge Rails resource routes use / as the URL separator for actions instead of ;. This will be in Rails 2.0 (and I like / more), so I wanted to get prepared for the change by updating my URLs now. I didn&#8217;t want to move to Edge Rails (too exciting for me), [...]]]></description>
			<content:encoded><![CDATA[<p>
As of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Rldi5ydWJ5b25yYWlscy5vcmcvY2hhbmdlc2V0LzY0ODU=">r6485</a>, Edge Rails resource routes use <b>/</b> as the URL separator for actions instead of <b>;</b>. This will be <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3ByYWdkYXZlLnByYWdwcm9nLmNvbS9wcmFnZGF2ZS8yMDA3LzAzL2NoYW5nZV90b19yZXN0Xy5odG1s">in Rails 2.0</a> (and I like / more), so I wanted to get prepared for the change by updating my URLs now. I didn&#8217;t want to move to Edge Rails (too exciting for me), so I grabbed the change, dropped it into a source file, and loaded it into my app (thank you, open classes).
</p>

<p>
If you want to get ready now, grab 
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=L3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDA3LzA0L3NsYXNoX3VybHMucmI="><kbd>slash_urls.rb</kbd></a> and drop it in your <kbd>lib</kbd> directory. At the top of your <kbd>config/routes.rb</kbd>, add the line:
</p>

<pre>&nbsp;
<span style="color: #000066;">require</span> <span style="color: #ff0000;">'slash_urls'</span></pre>

<p>
And now all my URLs on <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20=">NearbyGamers</a> use slashes instead of semicolons. I only had one or two actions on my ActiveResource routes besides the built-in CRUD, so I&#8217;m not worried about doing a 301 redirects.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=231" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/rails-semicolons-out-slashes-in/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Add Feed Discovery Links Easily</title>
		<link>http://push.cx/2007/add-feed-discovery-links-easily</link>
		<comments>http://push.cx/2007/add-feed-discovery-links-easily#comments</comments>
		<pubDate>Thu, 08 Mar 2007 12:39:34 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[atom]]></category>
		<category><![CDATA[auto_discovery_link_tag]]></category>
		<category><![CDATA[feeds]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://push.cx/2007/add-feed-discovery-links-easily</guid>
		<description><![CDATA[I&#8217;m working on discussion forums for NearbyGamers and I&#8217;m building the first feeds into the site. I worked up a clean way to add them from my controllers similar to my tidy stylesheets code. Here&#8217;s how to do it. In the &#60;head&#62; of your app/views/layouts/application.rhtml call the auto_discovery_link_tag to print the tags: &#160; &#60;%- @feeds.each [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;m working on discussion forums for <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20=">NearbyGamers</a> and I&#8217;m building the first feeds into the site. I worked up a clean way to add them from my controllers similar to my <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=ZWRpdGVkIA==">tidy stylesheets</a> code. Here&#8217;s how to do it.
</p>

<p>
In the &lt;head&gt; of your <kbd>app/views/layouts/application.rhtml</kbd> call the <kbd>auto_discovery_link_tag</kbd> to print the tags:
</p>

<pre>&nbsp;
  &lt;%- <span style="color: #0000ff;">@feeds</span>.<span style="">each</span> <span style="color: #b1b100;">do</span> |feed| -%&gt;
    &lt;%= auto_discovery_link_tag<span style="color: #66cc66;">&#40;</span>:atom, *feed<span style="color: #66cc66;">&#41;</span> %&gt;
  &lt;%- <span style="color: #b1b100;">end</span> -%&gt;</pre>

<p>
In <kbd>app/controllers/application.rb</kbd>:
</p>

<pre>&nbsp;
  def initialize
    <span style="color: #0000ff;">@feeds</span> = <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def add_feed title, options=<span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
    <span style="color: #0000ff;">@feeds</span> &lt;&lt; <span style="color: #66cc66;">&#91;</span> <span style="color: #66cc66;">&#123;</span> 
      :controller =&gt; self.<span style="">controller_name</span>, 
      :action =&gt; self.<span style="">action_name</span>, 
      :<span style="color: #000066;">format</span> =&gt; <span style="color: #ff0000;">'atom'</span> 
    <span style="color: #66cc66;">&#125;</span>.<span style="">update</span><span style="color: #66cc66;">&#40;</span>options<span style="color: #66cc66;">&#41;</span>, <span style="color: #66cc66;">&#123;</span> :title =&gt; title <span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#93;</span> 
  <span style="color: #b1b100;">end</span></pre>

<p>
And you&#8217;re all set up. Where you want an action to present feeds, call <kbd>add_feed</kbd>. After title, it takes options for url construction.
</p>

<pre>&nbsp;
  add_feed <span style="color: #ff0000;">'New discussions'</span>
  add_feed <span style="color: #ff0000;">'New posts'</span>, :action =&gt; <span style="color: #ff0000;">'posts'</span>, :sort_by =&gt; <span style="color: #ff0000;">'new'</span></pre>

<p>
It defaults to the current action with a format of &#8216;atom&#8217; so you can add feed code to your <kbd>respond_to</kbd> block. I&#8217;ll post again soon with code integrate <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Rldi5ydWJ5b25yYWlscy5vcmcvYnJvd3Nlci9wbHVnaW5zL3Jlc291cmNlX2ZlZWRlcj9yZXY9NTA5OA==">resource_feeder</a> to do this.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=229" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/add-feed-discovery-links-easily/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Colorizing Rails Test Output</title>
		<link>http://push.cx/2007/colorizing-rails-test-output</link>
		<comments>http://push.cx/2007/colorizing-rails-test-output#comments</comments>
		<pubDate>Tue, 06 Mar 2007 18:59:43 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[color]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[redgreen]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[test]]></category>

		<guid isPermaLink="false">http://push.cx/2007/colorizing-rails-test-output</guid>
		<description><![CDATA[I love making things easier to read, to skim, to take in at a glance. At last night&#8217;s the ChiRb presentation on rspec I noticed the output was nicely colorized. Hey, of course that&#8217;s easier to read. It&#8217;s also dead easy to add to your existing tests thanks to a gem by Pat Eyler, whether [...]]]></description>
			<content:encoded><![CDATA[<p>
I love making things easier to read, to skim, to take in at a glance. At <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2NoaXJiLm9yZy9ldmVudC9zaG93LzEz">last night&#8217;s</a> the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3J1Ynlmb3JnZS5vcmcvbWFpbG1hbi9saXN0aW5mby9jaGljYWdvZ3JvdXAtbWVtYmVycy1saXN0">ChiRb</a> presentation on <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3JzcGVjLnJ1Ynlmb3JnZS5vcmcv">rspec</a> I noticed the output was nicely colorized.
</p>

<p>
Hey, of course that&#8217;s easier to read. It&#8217;s also dead easy to add to your existing tests thanks to <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL29uLXJ1YnkuYmxvZ3Nwb3QuY29tLzIwMDYvMDYvbW9yZS1mdW4td2l0aC1yZWRncmVlbi5odG1s">a gem by Pat Eyler</a>, whether you call then with <kbd>rake test</kbd>, <kbd>rake test:units</kbd>, or <kbd>ruby test/functional/application_controller_test.rb</kbd>.
</p>

<pre>&nbsp;
$ sudo gem install redgreen</pre>

<p>
Edit your <kbd>test/test_helper.rb</kbd> and add <kbd>require 'redgreen'</kbd> after the other requires, and you&#8217;re done. If you run your tests, you&#8217;ll see something like:
</p>

<img class="important" src="http://push.cx/wp-content/uploads/2007/03/color_tests.png" alt="colorized test output" />

<p>
Passes are green, fails are red, errors are yellow. Here&#8217;s hoping you just see lots of green.
</p>

<p>
And rspec looks like good stuff, I&#8217;m going to add it to my test suite for <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20=">NearbyGamers</a>. The ability to test controllers without testing views (and vice-versa) will be a win.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=225" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/colorizing-rails-test-output/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 1.2.1 Impression</title>
		<link>http://push.cx/2007/rails-121-impression</link>
		<comments>http://push.cx/2007/rails-121-impression#comments</comments>
		<pubDate>Thu, 15 Feb 2007 02:52:24 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[assert_select]]></category>
		<category><![CDATA[assert_tag]]></category>
		<category><![CDATA[Barking Stapler]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2007/rails-121-impression</guid>
		<description><![CDATA[I&#8217;m updating NearbyGamers to Rails 1.2.1. Nothing broke except my use of assert_tag in my tests; it&#8217;s been long-regarded as squicky and has been replaced with assert_select. As I&#8217;m tidying up some deprecated code, it occurs to me that this makes for an interesting example of how I feel Rails is changing. Rails is growing [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;m updating <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20=">NearbyGamers</a> to Rails 1.2.1. Nothing broke except my use of <kbd>assert_tag</kbd> in my tests; it&#8217;s been long-regarded as squicky and has been replaced with <kbd>assert_select</kbd>. As I&#8217;m tidying up some deprecated code, it occurs to me that this makes for an interesting example of how I feel Rails is changing.
</p>

<p>
Rails is growing inwards and upwards, not just outwards. They&#8217;re finding better, terser, more Rails-ish ways to express things. They&#8217;re not piling on features, they&#8217;re condensing. <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNy9hbm5vdW5jaW5nLW5lYXJieWdhbWVycw==">I&#8217;ve mentioned</a> that this is what coding in Rails continually feels like: sometimes it just feels off even though it works and is nicer than other languages, and soon I realize a beautiful Right Way to do it.
</p>

<p>
Where Rails gained new features, the developers have redesigned functionality to make me think, &#8220;Wow, of course, that&#8217;s obviously much nicer&#8221; and it does more because it&#8217;s better-designed. Let me give you an example using <kbd>assert_tag</kbd>.
</p>

<p>
I&#8217;ve got tests that render pages and make sure they contain certain bits of HTML. One test used to be:
</p>

<pre>&nbsp;
assert_tag :tag =&gt; <span style="color: #ff0000;">"div"</span>,
           :attributes =&gt; <span style="color: #66cc66;">&#123;</span> :id =&gt; <span style="color: #ff0000;">'notice'</span> <span style="color: #66cc66;">&#125;</span>,
           :child =&gt; <span style="color: #66cc66;">&#123;</span>
             :tag =&gt; <span style="color: #ff0000;">"div"</span>,
             :content =&gt; text
           <span style="color: #66cc66;">&#125;</span></pre>

<p>And now it reads:</p>

<pre>&nbsp;
assert_select <span style="color: #ff0000;">"div#notice &gt; div"</span>, text</pre>

<p>
They rebuilt the assertion to use CSS selectors (with a few <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Jsb2cubGFibm90ZXMub3JnLzIwMDYvMDkvMDQvYXNzZXJ0X3NlbGVjdC1jaGVhdC1zaGVldC8=">clever additions</a>). Suddently the code is simpler, more idiomatic, and more featureful. And that&#8217;s just what coding Rails feels like.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=216" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/rails-121-impression/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Announcing NearbyGamers</title>
		<link>http://push.cx/2007/announcing-nearbygamers</link>
		<comments>http://push.cx/2007/announcing-nearbygamers#comments</comments>
		<pubDate>Mon, 22 Jan 2007 04:11:06 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Biz]]></category>
		<category><![CDATA[Barking Stapler]]></category>
		<category><![CDATA[NearbyGamers]]></category>
		<category><![CDATA[projects]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2007/announcing-nearbygamers</guid>
		<description><![CDATA[I&#8217;d like to invite you all to check out my newest project, NearbyGamers, a service for tabletop gamers to find other players. (As I mentioned earlier, it&#8217;s a Rails site.) It&#8217;s for people who play RPGs, CCGs, TCGs, wargames, board games &#8212; basically any game where you need to have a live human on the [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;d like to invite you all to check out my newest project, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL05lYXJieUdhbWVycy5jb20=">NearbyGamers</a>, a service for tabletop gamers to find other players. (As I <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNi9tYWtpbmctdmFsaWQteGh0bWwtZWFzaWVy">mentioned earlier</a>, it&#8217;s a Rails site.) It&#8217;s for people who play RPGs, CCGs, TCGs, wargames, board games &#8212; basically any game where you need to have a live human on the other side of a table if you want to play.
</p>

<img class="content" src="http://push.cx/wp-content/uploads/2007/01/NG-map.png" alt="NearbyGamers map screenshot" />

<p>
Basically it&#8217;s the mashup of a wiki and Google Maps, and I plan to add forums (there are very few things gamers like more than arguing online). I&#8217;ve been hacking at it on and off for a couple months now, and it&#8217;s finally worth talking about. NG is my first large Rails project, and it&#8217;s been a lot of fun. Almost all the time the code is quite dense and beautiful, but several times I&#8217;ve worked up some fairly ugly hackish code I&#8217;m not particularly happy with. And then a few days later an nice, friendly little solution will pop into my head, and it&#8217;s easy to hack in because I have comprehensive tests. (Having tests has really saved my life. I&#8217;ll be posting more about it, but for now I&#8217;ll just say that I couldn&#8217;t have built NG without automated tests.)
</p>

<p>
Some of the early beta testers are computer game fans, so there&#8217;s a fair number of computer games listed on NearbyGamers right now &#8212; heck, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vdGFnL1dvcmxkK29mK1dhcmNyYWZ0">World of Warcraft</a> is the most popular tag. I don&#8217;t see what folks will get out of it, but I&#8217;d rather build a pretty open system and let folks find new uses.
</p>

<p>
So check it out, let me know what you think. I&#8217;ve got a <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vdG9kby55bWw=">todo list</a> online for the curious, and I&#8217;m always taking suggestions.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=197" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/announcing-nearbygamers/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>GET and POST variable hashes in Ruby on Rails</title>
		<link>http://push.cx/2007/get-and-post-variable-hashes-in-ruby-on-rails</link>
		<comments>http://push.cx/2007/get-and-post-variable-hashes-in-ruby-on-rails#comments</comments>
		<pubDate>Mon, 08 Jan 2007 20:50:20 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://push.cx/2007/get-and-post-variable-hashes-in-ruby-on-rails</guid>
		<description><![CDATA[In Rails, you access GET, POST, and routing variables through the params hash. This works almost all the time, except when you duplicate a variable name: routing overwrites GET overwrites POST. For an app I&#8217;m working on I actually had to care where a variable comes from, so I dug for a while to find [...]]]></description>
			<content:encoded><![CDATA[<p>
In Rails, you access GET, POST, and routing variables through the <kbd>params</kbd> hash. This works almost all the time, except when you duplicate a variable name: routing overwrites GET overwrites POST.
</p>

<p>
For an app I&#8217;m working on I actually had to care where a variable comes from, so I dug for a while to find out how to access the raw hashes. It ain&#8217;t pretty, but here it is in case anyone else ends up needing it:
</p>

<pre>&nbsp;
get = CGIMethods.<span style="">parse_query_paremeters</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@request</span>.<span style="">query_string</span><span style="color: #66cc66;">&#41;</span>
post = CGIMethods.<span style="">parse_query_parameters</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@request</span>.<span style="">raw_post</span><span style="color: #66cc66;">&#41;</span> 
<span style="color: #808080; font-style: italic;"># you'd think you could use @request.query_parameters and</span>
<span style="color: #808080; font-style: italic;"># @request.request_parameters, but they're update()d by route vars</span>
route = <span style="color: #0000ff;">@request</span>.<span style="">path_parameters</span></pre>

<p class="aside">
(Also, don&#8217;t ask about this in #rubyonrails &#8212; you&#8217;ll just get lectured on how you don&#8217;t really want to access the hashes, how you should rename all your variables and URLs, and how it simply isn&#8217;t possible. This will be very frustrating and totally unproductive.)
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=193" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/get-and-post-variable-hashes-in-ruby-on-rails/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Making Valid XHTML Easier</title>
		<link>http://push.cx/2006/making-valid-xhtml-easier</link>
		<comments>http://push.cx/2006/making-valid-xhtml-easier#comments</comments>
		<pubDate>Tue, 14 Nov 2006 23:14:19 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://push.cx/2006/making-valid-xhtml-easier</guid>
		<description><![CDATA[I&#8217;m working on a Rails site in my Copious Free Time and I wanted to share a little way that Ruby made my life easier. I&#8217;m making my pages valid XHTML 1.0 Transitional because it makes life easier to find bugs and it just feels good to know I&#8217;m meeting the spec. The W3C Validator [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;m working on a Rails site in my <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2NhdGIub3JnL2phcmdvbi9odG1sL0MvY29waW91cy1mcmVlLXRpbWUuaHRtbA==">Copious Free Time</a> and I wanted to share a little way that Ruby made my life easier. I&#8217;m making my pages valid XHTML 1.0 Transitional because it makes life easier to find bugs and it just feels <i>good</i> to know I&#8217;m meeting the spec.
<p>

<p>
The <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3ZhbGlkYXRvci53My5vcmcv">W3C Validator</a> complained that I didn&#8217;t have the <kbd>rows</kbd> and <kbd>cols</kbd> attributes on my <kbd>&lt;textarea&gt;</kbd> tags. My code for them looked like:
</p>

<pre>&nbsp;
&lt;%= text_area_tag :message, params<span style="color: #66cc66;">&#91;</span>:message<span style="color: #66cc66;">&#93;</span> %&gt;</pre>

<p>
And I don&#8217;t want to add the <kbd>:size</kbd> option because I use CSS to style all of them, it&#8217;d be confusing to see an unused size there. So I extended the <kbd>text_area_tag</kbd> method in my <kbd>app/helpers/application_helper.rb</kbd> to fill in a default:
</p>

<pre>&nbsp;
module ApplicationHelper
  def text_area_tag<span style="color: #66cc66;">&#40;</span>name, content=nil, options=<span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>
    super<span style="color: #66cc66;">&#40;</span>name, content, <span style="color: #66cc66;">&#123;</span> :size =&gt; <span style="color: #ff0000;">"40x10"</span> <span style="color: #66cc66;">&#125;</span>.<span style="">update</span><span style="color: #66cc66;">&#40;</span>options<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
  <span style="color: #b1b100;">end</span>
end</pre>

<p>
And it was that easy to start having valid tags. I&#8217;ll be posting more Rails snippets and tips as I work on my project, and I&#8217;ll definitely announce here when it&#8217;s ready for wide release.
</p>

<p>
(This snippet owes thanks to &#8216;leethal&#8217; in #rubyonrails on <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2ZyZWVub2RlLm5ldA==">irc.freenode.net</a> for straightening out how I was trying to override the method.)
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=190" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/making-valid-xhtml-easier/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

