<?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: Productize your Rails App</title>
    <link>http://cwilliams.textdriven.com/articles/2005/07/25/productize-your-rails-app</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Ruby. Rails. Stuff.</description>
    <item>
      <title>Productize your Rails App</title>
      <description>&lt;p&gt;Duane Johnson &lt;a href="http://article.gmane.org/gmane.comp.lang.ruby.rails/14513"&gt;posted&lt;/a&gt; some interesting code to the Rails mailing list last week. Duane&amp;rsquo;s been creating Rails applications for clients, but to help actually make a profit, he&amp;rsquo;ll &amp;ldquo;re-sell&amp;rdquo; the work to other clients with some&amp;nbsp;custom-tailoring for each&amp;nbsp;particular client. He dubs this &amp;ldquo;productizing&amp;rdquo; his application. You can read &lt;a href="http://weblog.rubyonrails.com/archives/2005/07/12/productize-your-application-from-a-common-base"&gt;DHH&amp;rsquo;s original post highlighting this&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;So, he was looking for a way to keep a common codebase for all clients and still have a ay to explicitly tailor site-specific items, even beyond images or stylesheets &amp;ndash; but also to add or modify functionality. This post was particularly important to me, because this is exactly what I&amp;rsquo;ve been trying to&amp;nbsp;do with my Rails app. The aim is to create a common database model and common code as much as possible but to allow for site specific controllers, actions, or assets.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d been setting up Apache to use the subdomains to determine which site to present to the user. Initially I had them running off one rails instance and swapping the DB underneath by getting the subdomain. I also used the subdomain to swap layouts and other cases where I wanted things to differ. The biggest problem was that FastCGI and swapping the DB per request based on subdomain didn&amp;rsquo;t play nice together. The DB connections stayed open forever and eventually it all choked and died.&lt;/p&gt;
&lt;p&gt;Next I created two identical instances of the common code and had Apache just route to the right instance by virtual hosting. I just hard-coded the database.yml to point to the right database (and removed the swapping) for each instance. The rest of the code still looked at the subdomain to determine which layout to use, etc. Obviously my approaches left much to desire.&lt;/p&gt;
&lt;h3&gt;(Modified instructions for) "Productizing" your rails app&lt;/h3&gt;
&lt;p&gt;To anyone out there trying to follow Duane&amp;rsquo;s&amp;nbsp; approach, go read his post first, and then come back here, because some things are missing from his original post and some of what he tells there is not correct. Go ahead, &lt;a href="http://wiki.rubyonrails.com/rails/show/HowToProductizeYourApplication"&gt;read it&lt;/a&gt;,&amp;nbsp;and come on back&amp;hellip;&lt;/p&gt;
&lt;p&gt;OK, welcome back. If you&amp;rsquo;re actually playing along and are trying to get this working, follow Duane&amp;rsquo;s advice first and then go through what I have to get it working properly.&lt;/p&gt;
&lt;h3&gt;Open Issues / Caveats&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We haven&amp;rsquo;t worked out the work process of testing with this setup. (I also should note that I haven&amp;rsquo;t really tried playing with testing yet.)&lt;/li&gt;
&lt;li&gt;Routing will fail if you have a controller that only exists at the site level. For now, the workaround is to create an empty version of the controller at the top common-level.&lt;/li&gt;
&lt;li&gt;Some of what I give below is specific to Apache. I have not yet tried doing this with lighttpd, but I&amp;rsquo;m assuming that it would be fairly straight-forward to get this working with it.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;Apache Setup&lt;/h3&gt;
&lt;p&gt;Second, the way he told you to set up your document roots? Yeah that&amp;rsquo;s not exactly correct. Here&amp;rsquo;s what you do to get set up with Apache and FastCGI: &lt;/p&gt;
&lt;p&gt;Make sure you set your project folders up as Duane specified:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;RAILS_ROOT/
    app/
        controllers/
        views/
        (etc.)
    public/
    sites/
        best_ever_adoptions_co_inc/
            app/
                controllers/
                views/
            public/
        yet_another_adoption_co/
            app/
                controllers/
                views/
            public/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;Now, in each site&amp;rsquo;s public directory, copy over dispatch.fcgi. For each site-specific version of dispatch.fcgi, edit the line which includes environment.rb. You&amp;rsquo;ll be telling it to look up two directories higher than normal. Change the line to look like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;/../../../config/environment&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;You&amp;rsquo;ll probably be hosting all of these sites off the same server and Apache install. So here&amp;rsquo;s an example of my httpd.conf file where I use Virtual Hosts for each site. This is on Windows XP with Apache 2.x.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;LoadModule fastcgi_module modules/mod_fastcgi.so

&amp;lt;IfModule mod_fastcgi.c&amp;gt;
  AddHandler fastcgi-script .fcgi
  FastCgiServer C:/projects/svn/trunk/sites/site_one/public/dispatch.fcgi -initial-env site=site_one 
-initial-env RAILS_ENV=production -initial-env PATH=C:/oracle/ora81/bin -idle-timeout 200
  FastCgiServer C:/projects/svn/trunk/sites/site_two/public/dispatch.fcgi -initial-env site=site_two 
-initial-env RAILS_ENV=production -initial-env PATH=C:/oracle/ora81/bin -idle-timeout 200
&amp;lt;/IfModule&amp;gt;

NameVirtualHost *:80
&amp;lt;VirtualHost *:80&amp;gt;
    ServerName site_one.myhost.com
    DocumentRoot C:/projects/svn/trunk/sites/site_one/public
    ErrorLog C:/projects/svn/trunk/sites/site_one/log/apache.log
 
    &amp;lt;Directory C:/projects/svn/trunk/public/&amp;gt;
      Options ExecCGI FollowSymLinks
      AddHandler cgi-script .cgi
      AllowOverride all
      Order allow,deny
      Allow from all
    &amp;lt;/Directory&amp;gt;
    &amp;lt;Directory C:/projects/svn/trunk/sites/site_one/public/&amp;gt;
      Options ExecCGI FollowSymLinks
      AddHandler cgi-script .cgi
      AllowOverride all
      Order allow,deny
      Allow from all
    &amp;lt;/Directory&amp;gt;
  &amp;lt;/VirtualHost&amp;gt;
 
&amp;lt;VirtualHost *:80&amp;gt;
    ServerName site_two.myhost.com
    DocumentRoot C:/projects/svn/trunk/sites/site_two/public
    ErrorLog C:/projects/svn/trunk/sites/site_two/log/apache.log
    
    &amp;lt;Directory C:/projects/svn/trunk/public/&amp;gt;
      Options ExecCGI FollowSymLinks
      AddHandler cgi-script .cgi
      AllowOverride all
      Order allow,deny
      Allow from all
    &amp;lt;/Directory&amp;gt;
    &amp;lt;Directory C:/projects/svn/trunk/sites/site_two/public/&amp;gt;
      Options ExecCGI FollowSymLinks
      AddHandler cgi-script .cgi
      AllowOverride all
      Order allow,deny
      Allow from all
    &amp;lt;/Directory&amp;gt;
  &amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Getting Caching working right&lt;/h3&gt;
&lt;p&gt;Next, we&amp;rsquo;re going to modify Duane&amp;rsquo;s productize.rb file. Make sure it looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span class="comment"&gt;# productize.rb&lt;/span&gt;

&lt;span class="constant"&gt;SITE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;site&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;yet_another_adoption_co&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="constant"&gt;SITE_ROOT&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;sites&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="constant"&gt;SITE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;Dependencies&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;require_or_load&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;file_name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{file_name}&lt;/span&gt;.rb&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="punct"&gt;!&lt;/span&gt; &lt;span class="ident"&gt;load?&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="ident"&gt;file_name&lt;/span&gt; &lt;span class="punct"&gt;[-&lt;/span&gt;&lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;..-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;.rb&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;load?&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;load&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;require&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;include?&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;controller&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
      &lt;span class="ident"&gt;file_name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SITE_ROOT&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;app&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;controllers&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;  &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;basename&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
      &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;exist?&lt;/span&gt; &lt;span class="ident"&gt;file_name&lt;/span&gt;
        &lt;span class="ident"&gt;load?&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;load&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;require&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;file_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="constant"&gt;ActionController&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;page_cache_directory&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{SITE_ROOT}&lt;/span&gt;/public&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;

&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;ActionView&lt;/span&gt;
  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Base&lt;/span&gt;
    &lt;span class="ident"&gt;private&lt;/span&gt;
      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;full_template_path&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;template_path&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;extension&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
        &lt;span class="comment"&gt;# Check to see if the partial exists in our 'sites' folder  first&lt;/span&gt;
        &lt;span class="ident"&gt;site_specific_path&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SITE_ROOT&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;app&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;views&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;  &lt;span class="ident"&gt;template_path&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;extension&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

        &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;exist?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;site_specific_path&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
          &lt;span class="ident"&gt;site_specific_path&lt;/span&gt;
        &lt;span class="keyword"&gt;else&lt;/span&gt;
          &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{@base_path}&lt;/span&gt;/&lt;span class="expr"&gt;#{template_path}&lt;/span&gt;.&lt;span class="expr"&gt;#{extension}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; 
        &lt;span class="keyword"&gt;end&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What&amp;rsquo;s the difference? I&amp;rsquo;ve added a line which tells Rails to cache (and reload cached files) into the site specific directories. With Duane&amp;rsquo;s original code, the files would get cached at the top-level (so if the cached file was no generic enough, a site-specific version would be served up to every site).&lt;/p&gt;
&lt;h3&gt;Making the Assets Load in a Hierarchical Way&lt;/h3&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;One of the initial problems I had was that the assets &amp;ndash; images, javascripts, stylesheets &amp;ndash; had to be copied to every site&amp;rsquo;s public directory. Obviously we want common assets to behave like the code does &amp;ndash; try loading from the site specific directory, and then the common directory.&lt;/p&gt;
&lt;p&gt;I posed this to Duane and he responded with the following. Please note that I haven&amp;rsquo;t tried this yet, but it looks promising:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;I have an Apache solution to this problem: 

First, add an "Alias" directive inside of each VirtualHost, something like this:

FastCgiServer /Users/clifffano/Projects/premier/sites/premier_adoption/public/dispatch.fcgi 
-processes 1 -initial-env SITE=premier_adoption

&amp;lt;Directory "/Users/clifffano/Projects/premier/sites/premier_adoption/public/"&amp;gt;
    AllowOverride All
&amp;lt;/Directory&amp;gt;

# Remember to make sure "NameVirtualHost *:80" is set in httpd.conf so we can use VirtualHosts
&amp;lt;VirtualHost *:80&amp;gt;
    ServerName premier_adoption.localhost
    DocumentRoot /Users/clifffano/Projects/premier/sites/premier_adoption/public/

    # The following alias is important since it will allow this particular site to
    # seemlessly use the generic app's resources, e.g. images, javascripts etc. without
    # having to copy all files to the site-specific public/ folder:
    Alias /generic /Users/clifffano/Projects/premier/public/
&amp;lt;/VirtualHost&amp;gt;

Then, modify the site-specific dispatch.fcgi files, like so:

# Example:
#   RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On
RewriteRule ^$ index.html [QSA]

# If the requested file does not exist in SITE_ROOT/public...
RewriteCond %{REQUEST_FILENAME} !-f
# ... then split its full path up in to manageable pieces ...
RewriteCond %{REQUEST_FILENAME} ^(.*)/sites/.+/public/(.*)$
# ... and check to see if the file exists in the RAILS_ROOT/public folder...
RewriteCond %1/public/%2 -f
# ... if so, rewrite our requested file to be the RAILS_ROOT one
RewriteRule ^(.*)$ /generic/$1 [NS,L]

RewriteRule ^([^.]+)$ $1.html [QSA] 

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

This will skip Rails altogether and just send the appropriate files 
in the case that images, javascripts or html files exist in the 
generic public folder but not in the site-specific public folder.  
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Mon, 25 Jul 2005 15:20:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:9bb77bbe64f6d086014d4e7a478cf96d</guid>
      <author>cwilliams</author>
      <link>http://cwilliams.textdriven.com/articles/2005/07/25/productize-your-rails-app</link>
      <category>Programming</category>
      <category>Ruby</category>
      <category>Rails</category>
      <category>productize</category>
      <category>ruby</category>
      <category>Rails</category>
      <category>duane</category>
      <category>johnson</category>
    </item>
    <item>
      <title>"Productize your Rails App" by Buford</title>
      <description>I can't get my model files to be recognized in my site folder. If I put them at the top-level, they get loaded properly. I noticed that at the bottom of the default productize.rb that there is a "ToDo" for reloading model files.

I'd like to get that working but don't know what method to write or subclass. Any ideas on this ?</description>
      <pubDate>Thu, 10 Nov 2005 21:42:06 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a1c04456fd55b6e25da34a745be2cd09</guid>
      <link>http://cwilliams.textdriven.com/articles/2005/07/25/productize-your-rails-app#comment-110</link>
    </item>
    <item>
      <title>"Productize your Rails App" by Josh Martin</title>
      <description>Does your gem support productizing components also?  I have successfully implemented component controllers with a line in the enviroment.rb file, but that requires that the view exists in the productized component.  Is it possible to productize the views also?</description>
      <pubDate>Tue, 23 Aug 2005 20:07:39 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:cd5ae06a80a9afffab60cb652e100b21</guid>
      <link>http://cwilliams.textdriven.com/articles/2005/07/25/productize-your-rails-app#comment-68</link>
    </item>
    <item>
      <title>"Productize your Rails App" by duane.johnson@gmail.com</title>
      <description>Excellent write-up.  Thanks, Chris.

I've since created a gem that should fix all of the issues you've mentioned (well, here's hoping :)  It's the first release, but there's a lot going for it.  The announcement is at:

&lt;a href="http://thread.gmane.org/gmane.comp.lang.ruby.rails/16067"&gt;http://thread.gmane.org/gmane.comp.lang.ruby.rails/16067&lt;/a&gt;
</description>
      <pubDate>Tue, 26 Jul 2005 03:16:38 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:98a637308f0f4c0b48fed7a41b0d9913</guid>
      <link>http://cwilliams.textdriven.com/articles/2005/07/25/productize-your-rails-app#comment-64</link>
    </item>
  </channel>
</rss>
