<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Late to the Party: Tag Rails</title>
    <link>http://cwilliams.textdriven.com/articles/tag/rails?tag=rails</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Ruby. Rails. Stuff.</description>
    <item>
      <title>Aptana Studio 1.0 Released!</title>
      <description>&lt;p&gt;Wow it's been quite a while since I last posted. In the meantime I've been working hard on RDT and RadRails at Aptana and the job has been great. I'm very lucky to have found a way to work on the open source projects I love full-time.&lt;/p&gt;

&lt;p&gt;In that vein I'd like to announce that &lt;a href="http://www.aptana.com/blog/?p=200?diff=y"&gt;we've released the 1.0 of Aptana&lt;/a&gt;. This release is important for a number of reasons. First, we think the product is good-to-go for everyone. Second, we're announcing &lt;a href="http://www.aptana.com/products/studio_professional.php"&gt;a Pro version of the IDE&lt;/a&gt;. This version is for users who want to support the project so we can keep going, or who want the extra features and perks that come with a license: nightly build access, priority support, IE Javascript Debugger, SFTP/FTPS support and all sorts of other goodies. The support, nightly builds, SVN access also apply to the other components of what we're now calling Aptana Studio: &lt;a href="http://radrails.org/"&gt;RadRails&lt;/a&gt;, iPhone, PHP and AIR. So if you want to be on the bleeding edge of RadRails/RDT development you'll probably want to look into getting a license.&lt;/p&gt;

&lt;p&gt;Keep in mind that while we do offer a pro version for those who'd like to support us or the extra stuff, we are still shipping the same codebase (minus the commercial features) as &lt;a href="http://www.aptana.com/products/studio_community.php"&gt;an open source project under GPL&lt;/a&gt;. And we plan to remain an open-source company with an open source product.  Here's hoping that model will work for us!&lt;/p&gt;</description>
      <pubDate>Tue, 30 Oct 2007 12:41:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:494d8149-4863-4cca-bf1b-6c1d84350478</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2007/10/30/aptana-studio-1-0-released</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Rails</category>
      <category>aptana</category>
      <category>RDT</category>
      <category>radrails</category>
      <category>Rails</category>
      <category>ide</category>
    </item>
    <item>
      <title>Aptana backs RDT, hires me</title>
      <description>&lt;p&gt;I'm proud to announce today that &lt;a href="http://www.aptana.com"&gt;Aptana&lt;/a&gt; has hired me to work full-time on &lt;a href="http://rubyeclipse.sourceforge.net"&gt;RDT&lt;/a&gt;, RadRails and integrating that work with their existing Aptana IDE which focuses on CSS, HTML and Javascript.&lt;/p&gt;

&lt;div style="background-color: white; text-align: center;"&gt;&lt;a href="http://www.aptana.com/rdt.html"&gt;&lt;img src="/images/aptana_radrails_rdt_ajax_rails_blue.gif" alt=""aptana-radrails-rdt ajax on rails/&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;This announcement means that RDT will now have commercial backing (but will remain open-source and free!) and that you should see RDT and RadRails move forward at a much quicker pace than in the past.&lt;/p&gt;

&lt;p&gt;This is also great news for RadRails users and Rails developers in general as integrating the two will give you code completion, outlines, help, debugging and much more across the entire stack - from model to controller to the HTML, ruby code, CSS and Javascript that make up your views.&lt;/p&gt;

</description>
      <pubDate>Sat, 21 Apr 2007 16:41:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:c68f2859-5c20-4685-a61e-da26f1583f63</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2007/04/21/aptana-backs-rdt-hires-me</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Web design</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>aptana</category>
      <category>ruby</category>
      <category>Rails</category>
      <category>commercial</category>
      <category>sponsor</category>
      <category>RDT</category>
      <category>radrails</category>
      <category>ide</category>
      <category>eclipse</category>
      <category>announcement</category>
    </item>
    <item>
      <title>Multi-stage deployments with Capistrano</title>
      <description>&lt;p&gt;I'm seeing a recurring theme in my feed reader today - multi-stage deployments with Capistrano.
It seems that those of us working in larger companies have all hit the same issue - we have some form of user acceptance, staging or other system which mirrors the production in configuration; and we want to use Capistrano to deploy to it as well as production. I know that my current company has a 5-stage process for pushing out releases (we're in financial services, and very paranoid. Whether they'd ever accept Capistrano is another issue).&lt;/p&gt;

&lt;p&gt;So here are my lazy pointers to the discussions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ola Bini, who's been doing some great posts on ruby metaprogramming, &lt;a href="http://ola-bini.blogspot.com/2006/09/two-things-in-rails.html"&gt;calls out his need for a "production_test" environment&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://www.redhillconsulting.com.au/blogs/simon/archives/000359.html"&gt;Simon Harris&lt;/a&gt; shares some snippets of deploying to his staged server running mongrel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jamis Buck, the creator of Capistrano, weighed in a while ago on &lt;a href="http://weblog.jamisbuck.org/2006/1/3/using-switchtower-with-multiple-deployment-stages"&gt;multiple deployment stages&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Michael Buffington shares his Mongrel deployment for &lt;a href="http://www.michaelbuffington.com/articles/2006/09/11/mongrel-and-capistrano"&gt;multiple stages&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 29 Sep 2006 12:56:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:4759d294-d891-4627-9c37-a0d2fd01721f</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/09/29/multi-stage-deployments-with-capistrano</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>Rails</category>
      <category>capistrano</category>
      <category>deployment</category>
      <category>production</category>
      <category>webdev</category>
      <category>programming</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Prototype based Tag Autocompletion</title>
      <description>&lt;p&gt;I've been working on a website that uses tags internally. The &lt;a href="http://rubyforge.org/projects/taggable/"&gt;acts_as_taggable&lt;/a&gt; plugin has been great, but it only takes care of the ActiveRecord portion of tagging. One of the pieces of functionality I needed was to create an autocompleter for users to enter a list of tags on a record. Below is a pure copy-paste dump of my implementation. I'm not claiming it's good code or the right way top do things, but for those looking to use an autocompleter for a text field holding tags might find it useful. The implementation is close to that used by &lt;a href="http://del.icio.us"&gt;delicious&lt;/a&gt; in the tags field on posting new bookmarks.&lt;/p&gt;
&lt;p&gt;Here's an example usage:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_html "&gt;&lt;notextile&gt;&amp;lt;label for=&amp;quot;tags&amp;quot;&amp;gt;Tags&amp;lt;/label&amp;gt;
&amp;lt;%= text_field_tag 'tags', @tags.join(' '), :size =&amp;gt; 80, :autocomplete =&amp;gt; &amp;quot;off&amp;quot; %&amp;gt;
&amp;lt;div class=&amp;quot;auto_complete&amp;quot; id=&amp;quot;tags_auto_complete&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the prototype-based class in javascript. You'll probably want to stick this in your application.js file if you're using &lt;a href="http://www.rubyonrails.org"&gt;Rails&lt;/a&gt;.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_javascript "&gt;&lt;notextile&gt;String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') }

Autocompleter.Tag = Class.create();
Autocompleter.Tag.prototype = Object.extend(new Autocompleter.Base(), {
  lastEdit: '',
  currentTag: {},
  initialize: function(element, update, array, options) {
    this.baseInitialize(element, update, options);
    this.options.array = array;
  },
  
  getCurrentTag: function() {
	if(this.element.value == this.lastEdit) return true // no edit
	if(this.element == '') return false
	this.currentTag = {}
	var tagArray=this.element.value.toLowerCase().split(' '), oldArray=this.lastEdit.toLowerCase().split(' '), currentTags = [], matched=false, t,o
	for (t in tagArray) {
		for (o in oldArray) {
			if(typeof oldArray[o] == 'undefined') { oldArray.splice(o,1); break }
			if(tagArray[t] == oldArray[o]) { matched = true; oldArray.splice(o,1); break; }
		}
		if(!matched) currentTags[currentTags.length] = t
		matched=false
	}
	// more than one word changed... abort
	if(currentTags.length &amp;gt; 1) {
	  // hideSuggestions(); TODO Fix this!
	  return false;
	}
	this.currentTag = { text:tagArray[currentTags[0]], index:currentTags[0] }
	return true
  },

  getUpdatedChoices: function() {
    this.updateChoices(this.options.selector(this));
  },
  
  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         Event.stop(event);
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_UP:
         this.markPrevious();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')&amp;gt;0) Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.markNext();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')&amp;gt;0) Event.stop(event);
         return;
      }
     else 
       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
         (navigator.appVersion.indexOf('AppleWebKit') &amp;gt; 0 &amp;amp;&amp;amp; event.keyCode == 0)) return;
    this.lastEdit = this.element.value;

    this.changed = true;
    this.hasFocus = true;

    if(this.observer) clearTimeout(this.observer);
      this.observer = 
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
  },
  
  updateElement: function(selectedElement) {
    if (this.options.updateElement) {
      this.options.updateElement(selectedElement);
      return;
    }
    var value = '';
    if (this.options.select) {
      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
      if(nodes.length&amp;gt;0) value = Element.collectTextNodes(nodes[0], this.options.select);
    } else
      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
    
    var lastTokenPos = this.findLastToken();
    if (lastTokenPos != -1) {
      var newValue = this.element.value.substr(0, lastTokenPos + 1);
      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
      if (whitespace)
        newValue += whitespace[0];
      this.element.value = newValue + value;
    } else {
      tagArray = this.element.value.trim().split(' ')
      if (!this.getCurrentTag()) return;  // We had a problem getting the current tag, just return?
      tagArray[this.currentTag.index] = value;
      this.element.value = tagArray.join(' ');
    }
    this.element.focus();
    
    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
  },

  setOptions: function(options) {
    this.options = Object.extend({
      choices: 10,
      partialSearch: true,
      partialChars: 2,
      ignoreCase: true,
      fullSearch: false,
      selector: function(instance) {
          var ret       = []; // Beginning matches
        var partial   = []; // Inside matches
        var entry     = instance.getToken();
        
        entry = entry.trim().split(' ').pop()
        
        var count     = 0;

        for (var i = 0; i &amp;lt; instance.options.array.length &amp;amp;&amp;amp;  
          ret.length &amp;lt; instance.options.choices ; i++) { 

          var elem = instance.options.array[i];
          var foundPos = instance.options.ignoreCase ? 
            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
            elem.indexOf(entry);

          while (foundPos != -1) {
            if (foundPos == 0 &amp;amp;&amp;amp; elem.length != entry.length) { 
              ret.push(&amp;quot;&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;quot; + elem.substr(0, entry.length) + &amp;quot;&amp;lt;/strong&amp;gt;&amp;quot; + 
                elem.substr(entry.length) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
              break;
            } else if (entry.length &amp;gt;= instance.options.partialChars &amp;amp;&amp;amp; 
              instance.options.partialSearch &amp;amp;&amp;amp; foundPos != -1) {
              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
                partial.push(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + elem.substr(0, foundPos) + &amp;quot;&amp;lt;strong&amp;gt;&amp;quot; +
                  elem.substr(foundPos, entry.length) + &amp;quot;&amp;lt;/strong&amp;gt;&amp;quot; + elem.substr(
                  foundPos + entry.length) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);
                break;
              }
            }

            foundPos = instance.options.ignoreCase ? 
              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
              elem.indexOf(entry, foundPos + 1);

          }
        }
        if (partial.length)
          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
        return &amp;quot;&amp;lt;ul&amp;gt;&amp;quot; + ret.join('') + &amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;;
      }    
    }, options || {});
  }
});
      &lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 19 Sep 2006 15:12:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2abe1246-129f-45b9-816b-7809b386bd93</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2006/09/19/prototype-based-tag-autocompletion</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Web design</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>tags</category>
      <category>delicious</category>
      <category>ruby</category>
      <category>Rails</category>
      <category>autocomplete</category>
      <category>javascript</category>
      <category>prototype</category>
    </item>
    <item>
      <title>New Rails templates for AJAX</title>
      <description>&lt;p&gt;Those of you who are doing some heavy AJAX with Rails should check out &lt;a href="http://www.codyfauser.com/articles/2005/11/20/rails-rjs-templates"&gt;Cody Fauser's post&lt;/a&gt; about the new RJS templates supported by Rails. This allows you to extract all the javascript actions that should take place (effects, insertions, changing HTML dynamically) into a single template file. The concept is a bit different for those used to current templates. The current notion for templates is to produce some XML or HTML to present to the user. These templates allow you to define methods in the controller (that are called by AJAX calls, like link_to_remote) which handle traversing your model, just like in normal actions, but instead of placing your javascript code inside the RHTML template, you place the intended AJAX effects into an RJS template with the same name as the AJAX method/action in the controller. This may sound rather complicated, but it is actually easier to handle complex interactions with AJAX. The current helper methods tended to limit you to updating a single element as a result of various callbacks in the lifecycle of the AJAX method invokation. These templates will make it easy to define all the intended AJAX effects and results into a single place. Please note that this is in Edge Rails - the trunk of the subversion repository for now, so those wanting to try this out will need to download the trunk.&lt;/p&gt;</description>
      <pubDate>Tue, 29 Nov 2005 19:11:21 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:3cfb905e-9f2a-4daf-ac09-30bd1900438c</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2005/11/29/new-rails-templates-for-ajax</link>
      <category>Rails</category>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Web design</category>
      <category>Rails</category>
      <category>ajax</category>
      <category>template</category>
      <category>rjs</category>
    </item>
    <item>
      <title>Subversion Externals and Typo blogs</title>
      <description>&lt;p&gt;I've been running &lt;a href="http://typo.leetsoft.com"&gt;Typo&lt;/a&gt; as my blog engine for some time now, and keep my blog under version control with &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;. I have some minor modifications and configuration changes in my copy, but I strive to keep in tune with the Typo subversion trunk. So my question is: is there any way to set it up so that when I do an update that the core of my blog gets updated to the latest Typo code, but that my themes, modifications and configuration remain under my own version control? I assume there's some way to do it with svn:externals, but I'm not very experienced with that.&lt;/p&gt;
&lt;p&gt;Originally, I had minor modifications to the core Typo code in the views to customize some HTML output which may have made this more difficult (resorting to &lt;a href="http://svk.elixus.org/"&gt;SVK&lt;/a&gt; perhaps?), but now that themes can override views, I'll likely only have configuration (i.e. database.yml) and themes differing from the Typo core.&lt;/p&gt;</description>
      <pubDate>Wed, 09 Nov 2005 15:33:40 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:9980ffb565259689f0215bab8d9a0bdf</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2005/11/09/subversion-externals-and-typo-blogs</link>
      <category>Personal</category>
      <category>Rails</category>
      <category>Ruby</category>
      <category>typo</category>
      <category>blog</category>
      <category>subversion</category>
      <category>svn</category>
      <category>personal</category>
      <category>Rails</category>
    </item>
    <item>
      <title>Tutorial on implementing REST web services in Rails</title>
      <description>&lt;p&gt;Just a quick pointer to a &lt;a href="http://www.xml.com/pub/a/2005/11/02/rest-on-rails.html"&gt;nice article about implementing REST web service interfaces with Rails&lt;/a&gt;. The code snippets don't format so nicely, so it seems a little scary, but actually it does appear to be rather easy.&lt;/p&gt;</description>
      <pubDate>Fri, 04 Nov 2005 16:31:28 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:738f55164e759fa3ac9759bd73364a5e</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2005/11/04/tutorial-on-implementing-rest-web-services-in-rails</link>
      <category>Rails</category>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>REST</category>
      <category>web</category>
      <category>services</category>
      <category>ruby</category>
      <category>article</category>
    </item>
    <item>
      <title>Rails tip: Get Sneaky and cache pages with many parameters</title>
      <description>&lt;p&gt;So you're the coolest cat in town. You've been using Rails for like, at least a month now. Heck, you've even started getting caching working on your coolest new site. But wait a second. Your zeitgeist page has 4 fields which are passed around as parameters and you need to start caching the results badly, because Slashdot just posted about how brilliant your new site is. So what do you do?&lt;/p&gt;
&lt;p&gt;You watch as your site goes down in flames and weep uncontrollably.&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;No! Well, OK, maybe the first time. But after reading this you may be one step closer to avoiding the shame of sobbing like you just watched &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=ur2&amp;amp;camp=1789&amp;amp;tag=latetothepart-20&amp;amp;creative=9325&amp;amp;path=http://www.amazon.com/gp/product/B00003CXKS?v=glance%26n=130%26n=507846%26s=dvd%26v=glance"&gt;Dancer in the Dark&lt;/a&gt; and thought no one would be home for at least another hour.&lt;/p&gt;
&lt;p&gt;We'll use &lt;a href="http://typo.leetsoft.com"&gt;Typo&lt;/a&gt; and my own site, &lt;a href="http://www.pervwatch.org"&gt;pervwatch.org&lt;/a&gt; as examples to see how it's been tackled so far. Let's start with Pervwatch since that implementation is a little simpler. First, some context. Pervwatch is a Google Maps mashup. It combines Google Maps, &lt;a href="http://geocoder.us"&gt;geocoder.us&lt;/a&gt; data, and state sex offender registries to plot the location of sex offenders on a map. It allows you to see them all in one glance visually, where most sex offender registry websites show a single offender at a time on a map. The problem I had to tackle was that the pages for a number of the most populated counties in large states like California had too many results coming back. The pages became huge and the map was filled with too many markers. It slowed down users browsers, ate up browser memory, and took a long time to render on the server side. I could cache the results to eliminate the server side slowdown, but clients would still have problems. The easy solution is to paginate the results, right?&lt;/p&gt;
&lt;p&gt;Yes. But then what happens? If you paginate the results with Rails handy &lt;a href="http://api.rubyonrails.com/classes/ActionController/Pagination.html"&gt;pagination methods&lt;/a&gt;, and combine that with simple caching the first page rendered (and cached) will always be shown, no matter what. Why? Well Rails caches based on the URL, which doesn't include the extra parameter that pagination introduced (yet!), so requests for each of the following will resolve to the same cached file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://www.pervwatch.org/counties/map/152
http://www.pervwatch.org/counties/map/152?page=2
http://www.pervwatch.org/counties/map/152?page=12523&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Not so great. So how can I get around this? Easy, use Rails named routes! The default route is to assume URLs of the form:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/:controller/:action/:id&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can add a new route which is smarter and realizes that my county map pages may or may not be paginated. To accomplish this, we add the following to our RAILS_ROOT/config/routes.rb file:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;  &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;counties/map/:id/:page&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;counties&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="symbol"&gt;:requirements&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="symbol"&gt;:page&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;+&lt;/span&gt;&lt;span class="punct"&gt;/},&lt;/span&gt;
    &lt;span class="symbol"&gt;:page&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
    &lt;span class="symbol"&gt;:id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;+&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Fancy, huh? Here's what it means. Assume any URLs that match the format http://www.pervwatch.org/counties/map/id/page get resolved to the controller 'counties_controller', the action 'map'. Make sure the third part of the URL, is made up of digits only, and at least one (so make sure its a positive integer) - then assign that the the :id key in the params hash the 'map' method receives. The fourth part of the URL is optional (:page =&gt; nil), and if available, is also made only of digits - assign it to the :page key in the params hash passed to 'map'. Phew. That was a lot. Let's take a peek at the 'map' method to see what that means.&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;map&lt;/span&gt;
    &lt;span class="attribute"&gt;@county&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;County&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:id&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;
    &lt;span class="attribute"&gt;@pages&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="attribute"&gt;@offenders&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;paginate_collection&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@county&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;offenders&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:include&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:address&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:order&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;addresses.latitude DESC&lt;/span&gt;&lt;span class="punct"&gt;'),&lt;/span&gt; &lt;span class="symbol"&gt;:page&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:page&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="symbol"&gt;:per_page&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;250&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="comment"&gt;# ... some more code&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Counties don't have any easy unique field to identify them, so we stick with passing around the auto-generated primary key id (in params[:id]), as you can see in the first line. That seems to be the same as we've always operated. Now check the next line. Ignore the :include, :order stuff. See what we're doing? We're explicitly passing the params[:page] value into our paginate method. So now you see how the route looks, and how the action looks. But how does this help us any? We just want to cache all our pages uniquely.&lt;/p&gt;
&lt;p&gt;Take another look at the routes. You see, now when we pass in a 'page' parameter, Rails will compare against our routes and will &lt;em&gt;automatically match our new rules, expanding the page parameter value right into the URL if it exists!&lt;/em&gt; Lets do a side by side comparison of what the URLs used to look like and how they'll look now.&lt;/p&gt;

  &lt;h4&gt;Resolution of parameters to URLs with different routes.&lt;/h4&gt;
    
&lt;p&gt;params =&gt; {:controller =&gt; 'counties', :action =&gt; 'map', :id =&gt; 152}&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Old: http://www.pervwatch.org/counties/map/152&lt;/li&gt;
  &lt;li&gt;New: http://www.pervwatch.org/counties/map/152&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;params =&gt; {:controller =&gt; 'counties', :action =&gt; 'map', :id =&gt; 152, :page =&gt; 2}&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Old: http://www.pervwatch.org/counties/map/152?page=2&lt;/li&gt;
  &lt;li&gt;New: http://www.pervwatch.org/counties/map/152/2&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;params =&gt; {:controller =&gt; 'counties', :action =&gt; 'map', :id =&gt; 152, :page =&gt; 12523}&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Old: http://www.pervwatch.org/counties/map/152?page=12523&lt;/li&gt;
  &lt;li&gt;New: http://www.pervwatch.org/counties/map/152/12523&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aha! Nirvana. Now when Rails caches all the different pages for a given county, they won't all resolve and refer to one file! So hopefully by now you get the idea behind this. To be able to cache pages with more than the normal :controller / :action / :id parameters, you need to push the parameters into the URL. Now, let's look at a slightly more complicated example from Typo.&lt;/p&gt;
&lt;p&gt;Typo is blogging software built on Rails. In fact, this blog is running Typo. It's great, I love it. Typo had to tackle the pagination issue itself with routes, but they've also done some more complex neater things, such as finding all articles given a date, and to be able to cache the resulting page. They also can do this at a year level, monthly level and down to the exact date. So we could find everything in 2005, or everything in August 2005, or everything on August 18th, 2005. Neat idea, but we want to cache the results. This means we need to push those params into the URL. The side benefit allows for neat looking URLs that users could guess if they wanted to try and poke around.&lt;/p&gt;
&lt;p&gt;Here's what Typo stuck in their routes for this:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;  &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;articles/:year/:month/:day&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;articles&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;find_by_date&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="symbol"&gt;:year&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;{4}&lt;/span&gt;&lt;span class="punct"&gt;/,&lt;/span&gt; &lt;span class="symbol"&gt;:month&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;{1,2}&lt;/span&gt;&lt;span class="punct"&gt;/,&lt;/span&gt; &lt;span class="symbol"&gt;:day&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;{1,2}&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;
  &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;articles/:year/:month&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;articles&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;find_by_date&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="symbol"&gt;:year&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;{4}&lt;/span&gt;&lt;span class="punct"&gt;/,&lt;/span&gt; &lt;span class="symbol"&gt;:month&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;{1,2}&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;
  &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;articles/:year&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;articles&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;find_by_date&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="symbol"&gt;:year&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\d&lt;/span&gt;{4}&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a truncated version, they have more dealing with paginated results for the URLs like above, as well as many other different types of routes. So in their scheme, they're allowing for someone to specify year, month, and day (in that order) in the URL for the first route, and doing checking that the year must be four digits, the month one or two digits, and the day one or two digits. The second route allows the user to drop off the month parameter from the URL and still enforce the four digit year, and one or two digit month. The last allows just entering a year with four digits in the URL.&lt;/p&gt;
&lt;p&gt;I'll spare you the implementation code in the action and model. The idea behind it remains the same as with our pagination example. When you want to cache the results of a page which has important parameters that aren't :controller, :action or :id, then make a nice new route for it and specify the parameters inside the route. It's not only the easy way to get caching working right again, it also tends to lead you to better looking URLs for your users.&lt;/p&gt;

&lt;h3&gt;How does this affect url_for, link_to, etc?&lt;/h3&gt;
&lt;p&gt;Good question. Now when you write your link_to's you can switch your style just a little. Before you'd probably right like so:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;&lt;span class="punct"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="string"&gt; link_to 'Page 2', :controller &lt;/span&gt;&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;counties&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="attribute"&gt;@county&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:page&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="punct"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that can become:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;&lt;span class="punct"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="string"&gt; link_to 'Page 2', :controller &lt;/span&gt;&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;counties&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="attribute"&gt;@county&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:page&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt; &lt;span class="punct"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Think of it as a parameter getting "promoted" to URL member. It gets mentioned in the URL when we define the route, it gets grouped in with the other big guys like :action in our link_to, and it gets reflected in our cache. The parameter is getting a promotion.&lt;/p&gt;</description>
      <pubDate>Wed, 02 Nov 2005 21:03:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:eeffd848a6d0331d0544033614969dbe</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2005/11/02/rails-tip-get-sneaky-and-cache-pages-with-many-parameters</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>Rails</category>
      <category>ruby</category>
      <category>cache</category>
      <category>caching</category>
      <category>routes</category>
      <category>webdesign</category>
    </item>
    <item>
      <title>RadRails 0.2 Released, and RadRails' ancestry</title>
      <description>&lt;p&gt;I'd noticed the launch and subsequent talk of the new Ruby on Rails IDE, &lt;a href="http://www.radrails.org/"&gt;RadRails&lt;/a&gt;. The idea intrigued me, especially since I'm one of the lead developers on &lt;a href="http://rubyeclipse.sourceforge.net/"&gt;RDT&lt;/a&gt; and we'd heard a number of folks who had wanted to spin off their own Rails IDE separately or on top of RDT. The interest has been piqued yet again by today's anouncement of RadRails 0.2.&lt;/p&gt;
&lt;p&gt;RadRails is fairly impressive. It's a nice fully self-contained copy of Eclipse with the relevant plugins installed so all you do is unzip and double-click the executable. It has custom loading graphics, Rails project generation and all sorts of neat little helpers. So where did it come from and how'd they get a full Rails IDE up so fast?&lt;/p&gt;
&lt;p&gt;So, I took a peek inside the zip and I was slightly irked by one thing. RadRails &lt;strong&gt;is built on top of RDT&lt;/strong&gt; as well as the &lt;a href="http://subclipse.tigris.org/"&gt;Subclipse&lt;/a&gt; plugin. You wouldn't know that by their webpage, but they did mention us in the about dialog under the help menu. Not for nothing guys, but if you're building on top of RDT and Subclipse (not to mention &lt;a href="http://www.eclipse.org"&gt;Eclipse&lt;/a&gt;), it'd be nice to share the attribution and love. RDT could always use the support to drum up usage or more developers which in turn would help your own efforts...&lt;/p&gt;
&lt;p&gt;OK, personal rant aside, I do see a lot of improvements that they should consider. First, you have these wizards for generating new controllers or models. But they're hidden. You have to right click in the Rails Navigator, select Other... and then open the Rails folder to find these wizards. They should have nice big clickable icons up top on a menubar. Next, If I enter the name AccountsController in the controller wizard, you should be able to recognize that I typed Controller as a suffix and strip it out of the name before running the generator so I don't get accounts_controller_controller.rb generated. Third, try using the latest RDT 0.6.0 - it looks like you're running an old nightly build under the hood there because Rakefile and the Rails scripts are all not recognized as Ruby files and syntax highlighted, which they ought to be with 0.6.0. Fourth, the RI view we have in RDT? It doesn't look or work too well where you guys have moved it to be default. It should be fairly big like the console view in the bottom left, otherwise you can't read anything. Fifth, there should be shortcuts to show the other views RDT has such as the Test::Unit view or the Regexp view. They're still useful when developing a Rails project. &lt;/p&gt;</description>
      <pubDate>Tue, 04 Oct 2005 20:22:02 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:ca52814bdf7d3bbb43a7ab1881e49569</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2005/10/04/radrails-0-2-released-and-radrails-ancestry</link>
      <category>Programming</category>
      <category>Personal</category>
      <category>Rails</category>
      <category>Ruby</category>
      <category>ruby</category>
      <category>Rails</category>
      <category>radrails</category>
      <category>RDT</category>
      <category>eclipse</category>
      <category>plugin</category>
      <category>subclipse</category>
      <category>ide</category>
      <category>editor</category>
    </item>
    <item>
      <title>Rails Tip: What goes where (directory structure) - A cheat sheet</title>
      <description>&lt;p&gt;I work with Rails on a pretty much daily basis in my day job. While I own Agile Development with Rails, am subscribed to the Rails mailing list, and read a number of blogs where the authors touch on Rails I've been slow to pick up some of the subtleties of using the framework.&lt;/p&gt;
&lt;p&gt;A few coworkers also have all those resources available, but can't seem to wrap their heads around how the project is stuctured.&lt;/p&gt;

&lt;h3&gt;What Goes Where (or the Rails framework structure)&lt;/h3&gt;
&lt;p&gt;Rails defines a whole hierarchy of folders when you first generate a project. While some are very noticable in their intent, others can be confusing. Here's a simple breakdown of what goes where:&lt;/p&gt;
&lt;p&gt;&lt;a href="/files/rails_cheatsheet.gif"&gt;Rails Cheat Sheet (89.1 Kb)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While a lot of this should be simple and straightforward to pick up, I've found that I generally tend to get a little sloppy about my division of code between app/models, lib and vendor. Remember, if you didn't write it, it goes in vendor. If you wrote it and it doesn't derive from one of the big base classes of Rails (ActiveRecord, ActionMailer or Actioncontroller) it probably goes in lib - even if it is considered a "model" class. At least I like to try and follow that rule. Otherwise in complex apps you'll either end up with two undesirable results - you'll place tons of code in the controllers which could be encapsulated in lib models; or you'll end up putting all these custom models which have nothing to do with the Database in app/models and 'pollute' the folder - making it difficult to discern which models are DB abstractions and which are non-persistent.&lt;/p&gt;</description>
      <pubDate>Mon, 19 Sep 2005 19:59:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:4143e2f9dfb751ffe94274943b80a1d6</guid>
      <author>chris.a.williams@gmail.com (Chris)</author>
      <link>http://cwilliams.textdriven.com/articles/2005/09/19/rails-tip-what-goes-where-directory-structure</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>Rails</category>
      <category>ruby</category>
      <category>tips</category>
      <category>cheat</category>
      <category>sheet</category>
      <category>cheatsheet</category>
      <category>project</category>
      <category>structure</category>
      <category>hierarchy</category>
      <enclosure url="http://cwilliams.textdriven.com/files/rails_cheatsheet.gif" length="91249" type="image/gif"/>
    </item>
  </channel>
</rss>
