<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Webficient Blog - Home</title>
  <id>tag:www.webficient.com,2008:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  <link href="http://www.webficient.com/feed/posts.xml" rel="self" type="application/atom+xml"/>
  <link href="http://www.webficient.com/" rel="alternate" type="text/html"/>
  <updated>2008-07-02T07:38:52Z</updated>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-30:24</id>
    <published>2008-06-30T23:29:00Z</published>
    <updated>2008-07-02T07:38:52Z</updated>
    <category term="All"/>
    <category term="Benchmarks"/>
    <category term="performance"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/30/thin-web-server-benchmarks-using-ruby-on-rails" rel="alternate" type="text/html"/>
    <title>Thin Web Server Benchmarks using Ruby on Rails</title>
<content type="html">
            &lt;p&gt;In a &lt;a href=&quot;http://webficient.com/2008/6/24/ruby-enterprise-edition-and-passenger&quot;&gt;previous article&lt;/a&gt;, we looked at the performance and memory usage of a Ruby on Rails application running on Passenger Phusion (mod_rails). In this post, we&#8217;ll compare the same app running on the &lt;a href=&quot;http://code.macournoyer.com/thin/&quot;&gt;Thin Web server&lt;/a&gt; behind an Nginx cluster.&lt;/p&gt;


	&lt;h1&gt;Thin Basics&lt;/h1&gt;


	&lt;p&gt;Thin uses the Mongrel parser and Event Machine I/O library. In addition, it uses the &lt;a href=&quot;http://rack.rubyforge.org/&quot;&gt;Rack&lt;/a&gt; interface, allowing you to run other frameworks besides Ruby on Rails.&lt;/p&gt;


	&lt;p&gt;In a proxying scenario, where Nginx is the &#8220;front-end&#8221; for the Thin application server, you can leverage &lt;a href=&quot;http://lists.freebsd.org/pipermail/freebsd-performance/2005-February/001143.html&quot;&gt;Unix domain sockets&lt;/a&gt;, which can boost performance and memory usage. Not all &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; load balancers support it though.&lt;/p&gt;


	&lt;h1&gt;How We Tested&lt;/h1&gt;


	&lt;p&gt;To recap our testing configuration, we&#8217;re running a 512MB &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; slice (courtesy of Slicehost.com), and using Apache Bench to load test the login page of our Ruby on Rails blogging platform. This page is not cached but there isn&#8217;t a database call either, so our performance numbers don&#8217;t include any backend interaction. For other details, refer to the &#8220;Benchmark Overview&#8221; in our &lt;a href=&quot;http://webficient.com/2008/6/24/ruby-enterprise-edition-and-passenger&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Our first test used 4 Unix domain sockets, which are configured as follows, in nginx.conf:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;upstream webficient {&lt;tt&gt;
&lt;/tt&gt;  server unix:/tmp/thin.0.sock;&lt;tt&gt;
&lt;/tt&gt;  server unix:/tmp/thin.1.sock;&lt;tt&gt;
&lt;/tt&gt;  server unix:/tmp/thin.2.sock;&lt;tt&gt;
&lt;/tt&gt;  server unix:/tmp/thin.3.sock;&lt;tt&gt;
&lt;/tt&gt;}&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then, Thin was started up using&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;thin start -s4 --socket /tmp/thin.sock -e production&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;Results&lt;/h1&gt;


	&lt;p&gt;Memory usage under load using Thin/Nginx appeared better than mod_rails (with Ruby Enterprise Edition).&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;             total       used       free     shared    buffers     cached&lt;tt&gt;
&lt;/tt&gt;Mem:        524460     458272      66188          0       7060      82792&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Requests per second, on the other hand, were a bit slower than mod_rails (246 &lt;span class=&quot;caps&quot;&gt;RPS&lt;/span&gt; vs. 292 &lt;span class=&quot;caps&quot;&gt;RPS&lt;/span&gt; with mod_rails) but significantly faster than standard Mongrel.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Dynamic Content Load Test – Thin/Nginx&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Concurrency Level:      100&lt;tt&gt;
&lt;/tt&gt;Time taken for tests:   40.599507 seconds&lt;tt&gt;
&lt;/tt&gt;Complete requests:      10000&lt;tt&gt;
&lt;/tt&gt;Failed requests:        0&lt;tt&gt;
&lt;/tt&gt;Write errors:           0&lt;tt&gt;
&lt;/tt&gt;Total transferred:      30210000 bytes&lt;tt&gt;
&lt;/tt&gt;HTML transferred:       25690000 bytes&lt;tt&gt;
&lt;/tt&gt;Requests per second:    246.31 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       405.995 [ms] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       4.060 [ms] (mean, across all concurrent requests)&lt;tt&gt;
&lt;/tt&gt;Transfer rate:          726.63 [Kbytes/sec] received&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Seeing that we had a surplus of available memory during load testing, we tweaked the number of Unix domain sockets to evaluate the effect on overall performance. However, going from 4 to 5 sockets did not improve performance significantly. Dropping down to 3 sockets decreased performance. Therefore, our recommendation for a 512MB &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; slice is 4 sockets. In another test, we doubled Nginx&#8217;s number of &lt;em&gt;worker_processes&lt;/em&gt; from 3 to 6, however, this did not significantly improve Thin&#8217;s numbers either.&lt;/p&gt;


	&lt;h1&gt;Conclusion&lt;/h1&gt;


	&lt;p&gt;While slightly slower than mod_rails, Thin significantly outperforms a vanilla Mongrel Cluster/Nginx configuration. Thus, Thin is a viable solution to those who prefer Nginx to Apache. Recall that previous benchmarks show Nginx is the clear leader in serving up static content. So if your site uses caching extensively, you may want to consider this setup. Otherwise, Phusion Passenger will give you the best bang for the buck.&lt;/p&gt;


	&lt;p&gt;Another consideration is stability. Thin has been out for quite some time and has had 7 or so releases. Mod_rails is relatively new and not without issues, as seen in &lt;a href=&quot;http://groups.google.com/group/phusion-passenger&quot;&gt;its Google group&lt;/a&gt; and &lt;a href=&quot;http://nubyonrails.com/articles/ask-your-doctor-about-mod_rails&quot;&gt;blog posts&lt;/a&gt;. We&#8217;ll expect things to improve quickly in this area.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-30:25</id>
    <published>2008-06-30T23:00:00Z</published>
    <updated>2008-07-01T01:04:40Z</updated>
    <category term="All"/>
    <category term="Benchmarks"/>
    <category term="performance"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/30/using-ruby-enterprise-edition-with-nginx-mongrel" rel="alternate" type="text/html"/>
    <title>Using Ruby Enterprise Edition with Nginx/Mongrel</title>
<content type="html">
            &lt;p&gt;In a continuing series which benchmarks Phusion Passenger (mod_rails) against other popular Ruby Web serving configurations, today we&#8217;re looking at how a vanilla Mongrel cluster backend/Nginx frontend perform using the recently released &lt;a href=&quot;http://www.rubyenterpriseedition.com&quot;&gt;Ruby Enterprise Edition&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;For testing methodology and machine specs, please refer to the &lt;a href=&quot;http://webficient.com/2008/6/24/ruby-enterprise-edition-and-passenger&quot;&gt;first article&lt;/a&gt; in the series.&lt;/p&gt;


	&lt;h1&gt;No Impact on Memory Usage&lt;/h1&gt;


	&lt;p&gt;As already stated in the &lt;a href=&quot;http://www.rubyenterpriseedition.com/faq.html#mongrel&quot;&gt;Phusion Passenger FAQs&lt;/a&gt;, memory usage will not improve simply by using Ruby Enterprise Edition with Mongrel. This is due to the fact that Mongrel cannot leverage Ruby EE&#8217;s memory optimization routines without patching. It&#8217;ll be interesting to see this hurdle addressed by the community.&lt;/p&gt;


	&lt;h1&gt; Performance about the Same&lt;/h1&gt;


	&lt;p&gt;A Mongrel cluster powered by Ruby Enterprise Edition performed on par with a standard Ruby 1.8.6 virtual machine running on a 512MB &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; slice powered by Mongrel and Nginx.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Concurrency Level:      100&lt;tt&gt;
&lt;/tt&gt;Time taken for tests:   62.589211 seconds&lt;tt&gt;
&lt;/tt&gt;Complete requests:      10000&lt;tt&gt;
&lt;/tt&gt;Failed requests:        0&lt;tt&gt;
&lt;/tt&gt;Write errors:           0&lt;tt&gt;
&lt;/tt&gt;Total transferred:      30370000 bytes&lt;tt&gt;
&lt;/tt&gt;HTML transferred:       25690000 bytes&lt;tt&gt;
&lt;/tt&gt;Requests per second:    159.77 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       625.892 [ms] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       6.259 [ms] (mean, across all concurrent requests)&lt;tt&gt;
&lt;/tt&gt;Transfer rate:          473.85 [Kbytes/sec] received&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;Conclusion&lt;/h1&gt;


	&lt;p&gt;To realize the memory and performance numbers seen with previous benchmarks, your best bet is to use Ruby Enterprise Edition with Phusion Passenger/mod_rails.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-26:21</id>
    <published>2008-06-26T00:54:00Z</published>
    <updated>2008-07-03T17:20:43Z</updated>
    <category term="All"/>
    <category term="Benchmarks"/>
    <category term="performance"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/26/phusion-passenger-optimizations" rel="alternate" type="text/html"/>
    <title>Phusion Passenger Optimizations</title>
<content type="html">
            &lt;p&gt;In a &lt;a href=&quot;http://webficient.com/2008/6/24/ruby-enterprise-edition-and-passenger&quot;&gt;previous article&lt;/a&gt;, we installed and tested a baseline configuration of Phusion Passenger, aka mod_rails. In this post, we&#8217;ll be comparing memory usage and performance by varying Apache configuration settings in httpd.conf.&lt;/p&gt;


	&lt;p&gt;Realize that these numbers aren&#8217;t absolutes and will vary on your server, depending on its architecture, &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt;, and &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt;. Our &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; slice has the following specs:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Linux Fedora 8, 64-bit&lt;/li&gt;
		&lt;li&gt;512MB &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;Rails 2.0.2&lt;/li&gt;
		&lt;li&gt;Phusion Passenger 2.0.1&lt;/li&gt;
		&lt;li&gt;Enterprise Ruby 1.8.6 patchlevel 11&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;We used Apache Bench for testing:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# ab -n 10000 -c 100 http://server/app_path&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;PassengerMaxPoolSize&lt;/h1&gt;


	&lt;p&gt;&lt;em&gt;PassengerMaxPoolSize&lt;/em&gt; specifies the maximum number of Ruby on Rails application instances that may be simultaneously active. This setting has a lot of bearing on overall memory consumption and performance.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Memory Usage&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;PassengerMaxPoolSize    total       used       free     shared    buffers     cached&lt;tt&gt;
&lt;/tt&gt;        1              524460     417040     107420          0      21384     120216&lt;tt&gt;
&lt;/tt&gt;        2              524460     454740      69720          0      22560     127080&lt;tt&gt;
&lt;/tt&gt;        3              524460     489692      34768          0      23160     131860&lt;tt&gt;
&lt;/tt&gt;        4              524460     494548      29912          0      19860     110868&lt;tt&gt;
&lt;/tt&gt;        5              524460     516772       7688          0      19100     103628&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;http://webficient.com/assets/2008/6/26/mod_rails-memory.png&quot; alt=&quot;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;PassengerMaxPoolSize         Requests per second &lt;tt&gt;
&lt;/tt&gt;        1                    89.09 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;        2                   170.28 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;        3                   224.88 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;        4                   274.94 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;        5                   272.45 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;http://webficient.com/assets/2008/6/26/mod_rails-performance.png&quot; alt=&quot;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;


	&lt;p&gt;You&#8217;ll notice that our sweet spot is when &lt;em&gt;PassengerMaxPoolSize&lt;/em&gt; = 4, since we did not gain any more performance when set to 5, and less memory is used.&lt;/p&gt;


	&lt;h1&gt;PassengerMaxInstancesPerApp&lt;/h1&gt;


	&lt;p&gt;According to the &lt;a href=&quot;http://www.modrails.com/documentation/Users%20guide.html&quot;&gt;docs&lt;/a&gt;, &lt;em&gt;PassengerMaxInstancesPerApp&lt;/em&gt; is the maximum number of application instances that may be simultaneously active for a single application. The recommendation is to have the value be less than &lt;em&gt;PassengerMaxPoolSize&lt;/em&gt;. Trying different values, ranging from 1 to 3, we observed memory consumption to be a bit less, however the number of requests per second also suffered. We found that setting the value to 0, or no limit, produced the best results performance-wise. If you&#8217;re experiencing heavy swapping on a smaller slice, on the other hand, capping this value at something between 0 and &lt;em&gt;PassengerMaxPoolSize&lt;/em&gt; will help.&lt;/p&gt;


	&lt;h1&gt;Things that May Affect Benchmarks&lt;/h1&gt;


	&lt;p&gt;If you&#8217;re curious about seeing the impact of the above settings on your own configuration, be aware of the following.&lt;/p&gt;


	&lt;h2&gt;Heavy Swapping&lt;/h2&gt;


	&lt;p&gt;As physical memory is used up, your machine will start swapping virtual memory to disk. So be aware of any background processes already running. Disable any cron jobs, scheduled backups, etc.&lt;/p&gt;


	&lt;h2&gt;Linux IP Tables&lt;/h2&gt;


	&lt;p&gt;A software firewall like Linux IP Tables tracks each connection and temporarily persists a handle in a built-in database. It&#8217;s entirely possible to overwhelm the system, which will affect your numbers. Your Linux kernel log will show this message: &#8220;ip_conntrack: table full, dropping packet.&#8221; For an explanation of this issue and how to solve it, &lt;a href=&quot;http://www.cyberciti.biz/faq/ip_conntrack-table-ful-dropping-packet-error&quot;&gt;see this article&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-24:20</id>
    <published>2008-06-24T08:35:00Z</published>
    <updated>2008-07-01T01:06:13Z</updated>
    <category term="All"/>
    <category term="Benchmarks"/>
    <category term="performance"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/24/ruby-enterprise-edition-and-passenger" rel="alternate" type="text/html"/>
    <title>Ruby Enterprise Edition and Passenger</title>
<content type="html">
            &lt;p&gt;Recently, we evaluated &lt;a href=&quot;http://www.rubyenterpriseedition.com&quot;&gt;Ruby Enterprise Edition&lt;/a&gt; and Apache &lt;a href=&quot;http://www.modrails.com&quot;&gt;mod_rails&lt;/a&gt;, known as Phusion Passenger, in a &lt;a href=&quot;http://en.wikipedia.org/wiki/Virtual_private_server&quot;&gt;Virtual Private Server&lt;/a&gt; hosting environment. We compared performance and memory usage against our production instance, which runs this blog and uses an Nginx-powered Mongrel cluster.&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;[Editor&#8217;s note: new results have been published as of June 30, 2008.]&lt;/em&gt;&lt;/p&gt;


	&lt;h1&gt;Preparation&lt;/h1&gt;


	&lt;p&gt;First off, doing these kinds of evaluations is super easy with a &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; hosting service like &lt;a href=&quot;https://manage.slicehost.com/customers/new?referrer=1616112070&quot;&gt;Slicehost&lt;/a&gt;. We simply cloned a image of an existing production backup rather than building one from scratch. Then, we shut down Mongrel and Nginx.&lt;/p&gt;


	&lt;h1&gt;Installation&lt;/h1&gt;


	&lt;h2&gt;Ruby Enterprise Edition&lt;/h2&gt;


	&lt;p&gt;This was a breeze, following the &lt;a href=&quot;http://www.rubyenterpriseedition.com/download.html&quot;&gt;installation instructions&lt;/a&gt;.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# cd /usr/local/src&lt;tt&gt;
&lt;/tt&gt;# wget http://rubyforge.org/frs/download.php/38803/ruby-enterprise-1.8.6-20080624.tar.gz&lt;tt&gt;
&lt;/tt&gt;# tar xzvf ruby-enterprise-1.8.6-20080624.tar.gz&lt;tt&gt;
&lt;/tt&gt;# ./ruby-enterprise-1.8.6-20080624/installer&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The installer will check for the &lt;span class=&quot;caps&quot;&gt;GNU C&lt;/span&gt;++ compiler, and the Zlib and OpenSSL development headers, which are easy to install if you&#8217;re using a package manager like Yum on Fedora Linux.&lt;/p&gt;


	&lt;p&gt;The only hiccup we ran into was during the installation of the Enterprise Ruby-flavored version of the MySQL gem, getting the infamous &lt;strong&gt;&#8220;Failed to build gem native extension.&#8221;&lt;/strong&gt; Fortunately, the rest of the installation process went through smoothly. Afterwards, we used this command to install the MySQL gem:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# /opt/ruby-enterprise-1.8.6-20080624/bin/ruby /opt/ruby-enterprise-1.8.6-20080624/bin/gem install mysql -- --with-mysql-include=/usr/include/mysql --with-mysql-lib=/usr/lib64/mysql&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The Ruby Enterprise Edition executable is installed in a separate location so that you end up with two versions of Ruby on your machine. This means when installing new gems, you should use Ruby Enterprise Edition version. You can make this the default version by updating your environment settings:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;export PATH=/opt/{ruby enterprise edition folder}/bin/:$PATH&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Another gotcha is that the Ruby Enterprise Edition installer will install Rails 2.1.0. If you want 2.0.2, you&#8217;ll need to install it with&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;gem install rails -v 2.0.2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h2&gt;Passenger (mod_rails)&lt;/h2&gt;


	&lt;p&gt;Again, the installation process was simple per the &lt;a href=&quot;http://www.modrails.com/install.html&quot;&gt;docs&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;First, the gem:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# gem install passenger&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then, running the following command kick offs the installlation wizard.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# passenger-install-apache2-module&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Again, the installer checks for required dependencies and will advise you how to handle missing ones. In our case, we did not have Apache 2 and its development headers installed on our slice (since we were using Nginx).&lt;/p&gt;


	&lt;p&gt;The installation wizard will also tell you next steps for configuring Apache, which involves copying a few lines of settings. And to make Apache aware of your Rails app, it&#8217;s as simple as setting up a Virtual Host.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  ServerName www.webficient.com&lt;tt&gt;
&lt;/tt&gt;  DocumentRoot /u/apps/webficient/current/public&lt;tt&gt;
&lt;/tt&gt;&amp;lt;/VirtualHost&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Don&#8217;t forget to restart Apache for the changes to take:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# service httpd restart&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;(You can also use &lt;a href=&quot;http://www.modrails.com/documentation/Users%20guide.html#_redeploying_restarting_the_ruby_on_rails_application&quot;&gt;this technique&lt;/a&gt; if you don&#8217;t want to restart the entire httpd process).&lt;/p&gt;


	&lt;h1&gt;Benchmark Overview&lt;/h1&gt;


	&lt;p&gt;Because our blogging platform caches content, we looked at both dynamic and static content performance to ensure the numbers weren&#8217;t misleading. Our dynamic test involved hitting the login page. Our static test requested an existing cached article.&lt;/p&gt;


	&lt;p&gt;We used Apache Bench to simulate load:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# ab -n 10000 -c 100 http://server/app_path&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Both slices had the following aspects in common:
	&lt;ul&gt;
	&lt;li&gt;Linux Fedora 8, 64-bit&lt;/li&gt;
		&lt;li&gt;512MB &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;Rails 2.0.2&lt;/li&gt;
	&lt;/ul&gt;


The differences were type of application server and Ruby VM:
	&lt;ul&gt;
	&lt;li&gt;&#8220;Production&#8221; slice uses 3 Mongrels (v1.1.5), 3 Nginx (v0.6.31) worker processes (with 1,024 worker connections), and Ruby 1.8.6 patchlevel 114.&lt;/li&gt;
		&lt;li&gt;&#8220;Test&#8221; slice uses Passenger (mod_rails) and Enterprise Ruby 1.8.6 patchlevel 111. Based on the recommendations in the &lt;a href=&quot;http://www.modrails.com/documentation/Users%20guide.html&quot;&gt;Passenger documentation&lt;/a&gt;, we settled with a PassengerMaxPoolSize of 4, given the size of our &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt;.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h1&gt;Memory Usage&lt;/h1&gt;


	&lt;p&gt;Since we&#8217;re always interested in squeezing out every last meg of &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt; in our slice, we were curious to see how things fared under mod_rails and Ruby Enterprise Edition. Before running any benchmarks, it was clear that without the memory hungry Mongrels, our mod_rails test slice was quite a bit leaner.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Idle Comparison&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;             total       used       free     shared    buffers     cached&lt;tt&gt;
&lt;/tt&gt;mongrel:    524460     382736     141724          0      29816     118924&lt;tt&gt;
&lt;/tt&gt;mod_rails:  524460     241684     282776          0      21856     121256&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;em&gt;Be aware that Apache allocates very little memory until the first request comes in. You&#8217;ll expect to lose about 80 MB in free memory when that happens. So the above numbers will rarely be seen, unless you have a low traffic Web site.&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;As expected, memory usage surged during the load tests. With a PassengerMaxPoolSize equal to 4, mod_rails consumes more memory than the Mongrel/Nginx configuration. Setting it to 3 produced the opposite result. However, you&#8217;ll see this setting also affects requests per second.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Dynamic Content Test&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;             total       used       free     shared    buffers     cached&lt;tt&gt;
&lt;/tt&gt;mongrel:    524460     481800      42660          0      27488     116984&lt;tt&gt;
&lt;/tt&gt;mod_rails:  524460     500948      23512          0      20496     115360&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;strong&gt;Static Content Test&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;             total       used       free     shared    buffers     cached&lt;tt&gt;
&lt;/tt&gt;mongrel:    524460     439552      84908          0      29564     118908&lt;tt&gt;
&lt;/tt&gt;mod_rails:  524460     257604     266856          0      21544     121192&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;So under load, mod_rails can take it well. We are also thrilled that the mod_rails version of our blogging app is not leaking memory, unlike our Mongrel-powered production version.&lt;/p&gt;


	&lt;h1&gt;Performance&lt;/h1&gt;


	&lt;p&gt;What about speed? Results were in line with our expectations. Mod_rails does well serving up dynamic content but Nginx continues to dominate when static content is involved.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Dynamic Content &#8211; Mongrel/Nginx&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Although the numbers shown here represent a PassengerMaxPoolSize set to 4, we also ran the same tests with a value of 3. Number of requests per second decreased while memory usage improved.&lt;/em&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Concurrency Level:      100&lt;tt&gt;
&lt;/tt&gt;Time taken for tests:   63.843779 seconds&lt;tt&gt;
&lt;/tt&gt;Complete requests:      10000&lt;tt&gt;
&lt;/tt&gt;Failed requests:        0&lt;tt&gt;
&lt;/tt&gt;Write errors:           0&lt;tt&gt;
&lt;/tt&gt;Total transferred:      30370000 bytes&lt;tt&gt;
&lt;/tt&gt;HTML transferred:       25690000 bytes&lt;tt&gt;
&lt;/tt&gt;Requests per second:    156.63 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       638.438 [ms] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       6.384 [ms] (mean, across all concurrent requests)&lt;tt&gt;
&lt;/tt&gt;Transfer rate:          464.54 [Kbytes/sec] received&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;strong&gt;Dynamic Content &#8211; mod_rails/Ruby Enterprise Edition&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Concurrency Level:      100&lt;tt&gt;
&lt;/tt&gt;Time taken for tests:   34.190459 seconds&lt;tt&gt;
&lt;/tt&gt;Complete requests:      10000&lt;tt&gt;
&lt;/tt&gt;Failed requests:        0&lt;tt&gt;
&lt;/tt&gt;Write errors:           0&lt;tt&gt;
&lt;/tt&gt;Total transferred:      30900000 bytes&lt;tt&gt;
&lt;/tt&gt;HTML transferred:       25690000 bytes&lt;tt&gt;
&lt;/tt&gt;Requests per second:    292.48 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       341.905 [ms] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       3.419 [ms] (mean, across all concurrent requests)&lt;tt&gt;
&lt;/tt&gt;Transfer rate:          882.56 [Kbytes/sec] received&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;strong&gt;Static Content &#8211; Mongrel/Nginx&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Concurrency Level:      100&lt;tt&gt;
&lt;/tt&gt;Time taken for tests:   1.901919 seconds&lt;tt&gt;
&lt;/tt&gt;Complete requests:      10000&lt;tt&gt;
&lt;/tt&gt;Failed requests:        0&lt;tt&gt;
&lt;/tt&gt;Write errors:           0&lt;tt&gt;
&lt;/tt&gt;Total transferred:      540173910 bytes&lt;tt&gt;
&lt;/tt&gt;HTML transferred:       538042632 bytes&lt;tt&gt;
&lt;/tt&gt;Requests per second:    5257.85 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       19.019 [ms] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       0.190 [ms] (mean, across all concurrent requests)&lt;tt&gt;
&lt;/tt&gt;Transfer rate:          277358.28 [Kbytes/sec] received&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;strong&gt;Static Content &#8211; mod_rails/Ruby Enterprise Edition&lt;/strong&gt;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Concurrency Level:      100&lt;tt&gt;
&lt;/tt&gt;Time taken for tests:   2.550226 seconds&lt;tt&gt;
&lt;/tt&gt;Complete requests:      10000&lt;tt&gt;
&lt;/tt&gt;Failed requests:        0&lt;tt&gt;
&lt;/tt&gt;Write errors:           0&lt;tt&gt;
&lt;/tt&gt;Total transferred:      540430000 bytes&lt;tt&gt;
&lt;/tt&gt;HTML transferred:       537720000 bytes&lt;tt&gt;
&lt;/tt&gt;Requests per second:    3921.22 [#/sec] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       25.502 [ms] (mean)&lt;tt&gt;
&lt;/tt&gt;Time per request:       0.255 [ms] (mean, across all concurrent requests)&lt;tt&gt;
&lt;/tt&gt;Transfer rate:          206947.55 [Kbytes/sec] received&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;We&#8217;re Not Done Yet&lt;/h1&gt;


	&lt;p&gt;Although we like what we see so far, we&#8217;re going to run some additional tests and analysis, including:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://webficient.com/2008/6/26/phusion-passenger-optimizations&quot;&gt;Isolating optimal Apache and Passenger settings for handling load while keeping memory usage within limits&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://webficient.com/2008/6/30/using-ruby-enterprise-edition-with-nginx-mongrel&quot;&gt;Evaluating a Nginx/Mongrel/Ruby Enterprise Edition stack&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://webficient.com/2008/6/30/thin-web-server-benchmarks-using-ruby-on-rails&quot;&gt;Comparing memory usage and performance against the Thin Web server&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;We&#8217;ll post our findings in the near future.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-21:11</id>
    <published>2008-06-21T07:30:00Z</published>
    <updated>2008-06-24T08:39:43Z</updated>
    <category term="All"/>
    <category term="Solutions"/>
    <category term="Working Faster"/>
    <category term="capistrano"/>
    <category term="performance"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/21/pre-caching-ruby-on-rails-views-application-deployment" rel="alternate" type="text/html"/>
    <title>Pre-Caching Rails Views During Application Deployment</title>
<content type="html">
            &lt;p&gt;If you&#8217;re caching any pages in your Rails app as a performance enhancer, you may find this post useful. If your Web application gets a decent amount of traffic, then waiting for Rails to cache your Action View templates as &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, post-deployment, is not ideal. While people are banging on your site, the &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; is spiking, things are queuing, and everything slows down.&lt;/p&gt;


	&lt;p&gt;We&#8217;ve cooked up a &lt;a href=&quot;http://capify.org&quot;&gt;Capistrano&lt;/a&gt; recipe that leverages the Ruby &lt;a href=&quot;http://mechanize.rubyforge.org/mechanize/&quot;&gt;Mechanize gem&lt;/a&gt; and crawls your application, starting at the site index or any page you specify. So instead of sitting there and clicking each link, learn about how you can use this Cap task to enhance your next project.&lt;/p&gt;


	&lt;h1&gt;Features&lt;/h1&gt;


	&lt;ul&gt;
	&lt;li&gt;Able to crawl local or remotely hosted application&lt;/li&gt;
		&lt;li&gt;Crawling limited to application pages, does not follow external links&lt;/li&gt;
		&lt;li&gt;Ignores links pointing to non-HTML content&lt;/li&gt;
		&lt;li&gt;Traps &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; errors and moves on to next item&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h1&gt;Installation&lt;/h1&gt;


	&lt;p&gt;First, be sure you have the Mechanize gem installed:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;sudo gem install mechanize&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Next, inside your Rails app, create a new file at ../lib/tasks/crawler.rb:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mechanize&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Crawler&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;EXTENSIONS_IGNORED&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%w[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.csv .doc .docx .gif .jpg .jpeg .js .mp3 &lt;tt&gt;
&lt;/tt&gt;          .mp4 .mpg .mpeg .pdf .png .ppt .rss .swf .txt .xls .xlsx .xml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;initialize&lt;/span&gt;(starting_url, history_size = &lt;span class=&quot;i&quot;&gt;1000&lt;/span&gt;)    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@agent&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;WWW&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Mechanize&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@agent&lt;/span&gt;.history.max_size = history_size&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@starting_url&lt;/span&gt; = starting_url&lt;tt&gt;
&lt;/tt&gt;    extract_and_call_urls(starting_url)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;extract_and_call_urls&lt;/span&gt;(url)    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;#catch any non-html doc types up front and exit    &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;EXTENSIONS_IGNORED&lt;/span&gt;.detect{ |ext| url =~ &lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;ext&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt; } != &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;#get page&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    puts &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;url: &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;url&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;begin&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      page = &lt;span class=&quot;iv&quot;&gt;@agent&lt;/span&gt;.get(url)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;rescue&lt;/span&gt; =&amp;gt; exception&lt;tt&gt;
&lt;/tt&gt;      puts exception.message&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;#for any content types we may have missed above, &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;#exit if content type is not html&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; page.content_type.index(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;text/html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;#get links found on page&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    links = page.links&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;#for each link, call the url if not in history&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    links.each{ |link| extract_and_call_urls(link.href) &lt;span class=&quot;r&quot;&gt;unless&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@agent&lt;/span&gt;.visited?(link.href) || invalid_url?(link.href) }&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  private&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;invalid_url?&lt;/span&gt;(url)&lt;tt&gt;
&lt;/tt&gt;    (url.index(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) != &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; || &lt;tt&gt;
&lt;/tt&gt;    url.index(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ftp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) != &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; || &lt;tt&gt;
&lt;/tt&gt;    url.index(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;mailto&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) != &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt;) &amp;amp;&amp;amp;&lt;tt&gt;
&lt;/tt&gt;    url.index(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://localhost&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp;&lt;tt&gt;
&lt;/tt&gt;    url.index(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://127.0.0.1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Now, you need to make the above functionality available as a Capistrano task. Add this line to the top of config/deploy.rb:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/lib/tasks/crawler&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;And at the bottom of deploy.rb, add this task:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;desc &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Crawl pages using the Mechanize gem. Optionally set URL variable &lt;tt&gt;
&lt;/tt&gt;      as the starting point.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class=&quot;sy&quot;&gt;:crawl_pages&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  start_url = &lt;span class=&quot;co&quot;&gt;ENV&lt;/span&gt;[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] || &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://localhost:3000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;Crawler&lt;/span&gt;.new(start_url)&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;Usage&lt;/h1&gt;


	&lt;p&gt;As with any other Capistrano task, you&#8217;ll need to use your command line shell within your application&#8217;s directory. Check out &lt;a href=&quot;http://labs.peritor.com/webistrano&quot;&gt;Webistrano&lt;/a&gt; if you prefer running Capistrano tasks from your browser.&lt;/p&gt;


	&lt;p&gt;There are several ways you can apply the crawl_pages tasks. You can run the command on your development machine, add the files to your source code repository, and they&#8217;ll be automatically included in your next deployment to production. This approach mostly makes sense for pages with static content.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;cap crawl_pages&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;If, however, your content is dynamic (perhaps generated by a content management system), then you&#8217;ll need to run the task against your live site. The way the task is written allows you to run the command from your local machine by specifying a remote &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;. However, the task limits itself to crawling only pages associated with the site.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;cap crawl_pages URL=http://mysiteurl.com&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;Automatic Crawling&lt;/h1&gt;


	&lt;p&gt;If you&#8217;d like the crawler task to fire off automatically, just add the following line to deploy.rb:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;after &lt;span class=&quot;sy&quot;&gt;:deploy&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:crawl_pages&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;after &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;deploy:migrations&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:crawl_pages&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h1&gt;Other Uses&lt;/h1&gt;


	&lt;p&gt;Besides pre-caching pages, you can also use the crawler task to check for broken links and exceptions. Any &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; exception will be trapped and displayed in the command line output. For exceptions, you can correlate the problem in the server log, or if you have the slick &lt;a href=&quot;http://agilewebdevelopment.com/plugins/exception_notifier&quot;&gt;Exception Notifier&lt;/a&gt; plugin installed, you&#8217;ll receive an email with the juicy details.&lt;/p&gt;


	&lt;p&gt;Enjoy!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-20:13</id>
    <published>2008-06-20T08:55:00Z</published>
    <updated>2008-06-20T08:56:46Z</updated>
    <category term="All"/>
    <category term="Patterns"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/20/keeping-domain-logic-out-of-ruby-on-rails-views" rel="alternate" type="text/html"/>
    <title>Keeping Domain Logic Out of Views</title>
<content type="html">
            &lt;p&gt;A typical Rails application includes domain logic and presentation logic. Domain logic &#8211; often called &#8220;business logic&#8221; &#8211; includes algorithms, calculations, rules, etc. applicable to your models.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Employee&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;recently_hired?&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now.months_ago(&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;) &amp;lt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.hire_date&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Presentation logic, on the other hand, affects the rendering of elements in the user interface.&lt;/p&gt;


	&lt;p&gt;(/employees/_employee.html.erb):&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; div_for employee &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; employee.recently_hired? &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ...employee details...&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The problem is when domain logic leaks into Views and begins to take on the responsibility of presentation logic.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; div_for employee &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now.months_ago(&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;) &amp;lt; employee.hire_date   &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ...employee details...&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The above rule may change, perhaps Human Resources decides &#8220;recently hired&#8221; includes anyone hired this past quarter. So in this case, a change in domain logic would require you to change your View code. Further, if you needed to evaluate this condition in other Views, you&#8217;d have unnecessary code duplication that now needs to be maintained in more than one spot.&lt;/p&gt;


	&lt;p&gt;Looking back at the second code snippet, you may be thinking, doesn&#8217;t the following smell like domain logic?&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; employee.recently_hired? &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;...employee details...&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;And what happens when requirements change, and now we have to also consider employment status&#8230;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; div_for employee &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; employee.recently_hired? &amp;amp;&amp;amp; employee.full_time? &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ...employee details...&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Again, it seems like changes to domain requirements would require us to maintain the View. This may not seem like a big deal when you&#8217;ve got a handful of templates, but in a larger application, where there may be a few developers actively working on the project, these things matter.&lt;/p&gt;


	&lt;p&gt;So why not handle it by pushing back into the model and doing something like&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Employee&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;displayable?&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.recently_hired? &amp;amp;&amp;amp; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.full_time?&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;With the above, we&#8217;ve now attached presentation logic to the model. Whether something is &#8220;displayable&#8221; should not be the concern of a model, especially when it&#8217;s not aware of the context the data is being used.&lt;/p&gt;


	&lt;p&gt;Fortunately, Rails &lt;a href=&quot;http://wiki.rubyonrails.org/rails/pages/HowtoWorkWithHelpers&quot;&gt;Helpers&lt;/a&gt; allow us to pull anything that resembles domain logic out of the View completely but still influence what the user sees in the View:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;EmployeesHelper&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;display_employee&lt;/span&gt;(employee)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;if&lt;/span&gt; employee.recently_hired? &amp;amp;&amp;amp; employee.full_time?&lt;tt&gt;
&lt;/tt&gt;      content_tag(&lt;span class=&quot;sy&quot;&gt;:div&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;employee.full_name&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;employee.hire_date&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;...as well as simplifying the View:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; div_for employee &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%=&lt;/span&gt; display_employee(employee) &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Several use cases, in which helpers are handy for evaluating a model and generating presentation logic, include:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Dynamically inserting &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; selectors into markup&lt;/li&gt;
		&lt;li&gt;Evaluating whether text should be hyperlinked&lt;/li&gt;
		&lt;li&gt;Changing the layout (markup) of the screen&lt;/li&gt;
	&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-18:14</id>
    <published>2008-06-18T22:57:00Z</published>
    <updated>2008-06-20T09:04:00Z</updated>
    <category term="All"/>
    <category term="Resources"/>
    <category term="aws"/>
    <link href="http://www.webficient.com/2008/6/18/amazon-web-services-ec2-image" rel="alternate" type="text/html"/>
    <title>Amazon Web Services EC2 Image</title>
<content type="html">
            &lt;p&gt;If you ever dabble with Amazon&#8217;s Elastic Compute Cloud and need a reliable image prepackaged with Ruby on Rails, Nginx, and more, you can &lt;a href=&quot;http://developer.amazonwebservices.com/connect/entry.jspa?categoryID=101&amp;amp;#38;externalID=1235&quot;&gt;download our public &lt;span class=&quot;caps&quot;&gt;AMI&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-06-11:10</id>
    <published>2008-06-11T08:00:00Z</published>
    <updated>2008-06-21T07:53:05Z</updated>
    <category term="All"/>
    <category term="Solutions"/>
    <category term="performance"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/6/11/improving-performance-ruby-on-rails-models" rel="alternate" type="text/html"/>
    <title>Improving Performance in Ruby on Rails Models</title>
<content type="html">
            &lt;p&gt;The &lt;a href=&quot;http://en.wikipedia.org/wiki/Active_record_pattern&quot;&gt;Active Record&lt;/a&gt; design pattern simplifies data access in Rails applications. But you can also shoot yourself in the foot performance-wise if you misapply it to queries that span multiple objects and instances. In this article, we look at ways you can improve query performance.&lt;/p&gt;


	&lt;h2&gt;A Good Measure&lt;/h2&gt;


	&lt;p&gt;So where does one start? As a rule of thumb, always optimize the slowest queries first. It sounds obvious but you&#8217;d be surprised. Use the application log to get a general sense of which queries are taking the longest. You can also apply the &#8220;benchmark&#8221; method&#8212;available in several key places:&lt;/p&gt;


	&lt;p&gt;Inside models:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.get_active&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.benchmark &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Get Active Contacts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;    find_all_by_status(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Inside controllers (acting upon a model):&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.benchmark &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Get Active Contacts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;iv&quot;&gt;@active_contacts&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.get_active&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Inside views:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;% benchmark &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Show Active Contacts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;%= @active_contacts %&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;% &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;A cool feature is the ability to string multiple benchmarks together as follows:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.benchmark &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;First Way&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;iv&quot;&gt;@active_contacts&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.get_active_test1&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.benchmark &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Second Way&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;iv&quot;&gt;@active_contacts&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.get_active_test2&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.benchmark &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Third Way&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;iv&quot;&gt;@active_contacts&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.get_active_test3&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;which then appears in your app log like this&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;First Way (0.65363)&lt;tt&gt;
&lt;/tt&gt;Second Way (0.56675)&lt;tt&gt;
&lt;/tt&gt;Third Way (0.54476)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Beyond these basics, you can explore the many &lt;a href=&quot;http://whynotwiki.com/Rails_/_Performance&quot;&gt;profiling tools&lt;/a&gt; available to Ruby programmers.&lt;/p&gt;


	&lt;h2&gt;Including Data Upfront&lt;/h2&gt;


	&lt;p&gt;Often, you need to display a model instance and its related associations. Example: a company view also displays a list of related contacts. Active Record permits you to retrieve as much data as you need using the &#8216;include&#8217; symbol; this is often referred to as &#8216;eager loading of associations.&#8217;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;companies = &lt;span class=&quot;co&quot;&gt;Company&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;                         &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt; =&amp;gt; &lt;span class=&quot;sy&quot;&gt;:contacts&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;                         &lt;span class=&quot;sy&quot;&gt;:conditions&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;contacts.status = 'Active'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Behind the scenes, the &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement will include a join to the related table(s).&lt;/p&gt;


	&lt;p&gt;However, the previous example does not always result in better performance. While you can significantly cut down on the number of roundtrips to the database, the amount of data returned, to be processed by Ruby code and wrapped into an Active Record object, can in fact slow things down. This is especially true if your model contains a lot of attributes.&lt;/p&gt;


	&lt;p&gt;One way to speed things up is to only load the columns needed to support the view. Going back to the company example, we only care about showing contacts&#8217; names and email addresses.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;companies = &lt;span class=&quot;co&quot;&gt;Company&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;                         &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt; =&amp;gt; &lt;span class=&quot;sy&quot;&gt;:contacts&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;                         &lt;span class=&quot;sy&quot;&gt;:select&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;companies.*, contacts.first_name, &lt;tt&gt;
&lt;/tt&gt;                                     contacts.last_name, contacts.email&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;                         &lt;span class=&quot;sy&quot;&gt;:conditions&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;contacts.status = 'Active'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h2&gt;A Little Bit of Ruby Love&lt;/h2&gt;


	&lt;p&gt;Depending on the size of your database, sometimes it&#8217;s faster to retrieve &lt;span class=&quot;caps&quot;&gt;ALL&lt;/span&gt; of the rows for a given model and then use Ruby&#8217;s sophisticated array handling capabilities to parse through the collection.&lt;/p&gt;


	&lt;p&gt;For example, let&#8217;s say we&#8217;re generating a report that counts the number of active contacts for all companies in the system. As the number of contacts grow, the following snippet will result in longer execution time. The &#8216;find_all_by_status&#8217; method results in another database call for each company instance:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Company&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;).each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |company|&lt;tt&gt;
&lt;/tt&gt;  puts company.contacts.find_all_by_status(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
 

	&lt;p&gt;The following alternative gets us down to two database calls:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;active_contacts = &lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.find_all_by_status(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;Company&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;).each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |company|&lt;tt&gt;
&lt;/tt&gt;  puts active_contacts.select{ |contact| contact.company_id == company.id }&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;What about the :include symbol? In some of our data access tests, the above variation proved to be faster than eagerly loading associations. Our guess is the construction of the larger &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement is a bit slower than two simple &#8220;select *&#8221; calls. Again, use the Benchmark functions to see for yourself. Only testing will help you come to your own conclusions.&lt;/p&gt;


	&lt;h2&gt;Are You (De)Normal?&lt;/h2&gt;


	&lt;p&gt;If you have a summary value that is expensive to calculate (i.e. requires multiple database roundtrips and/or a complex block of Ruby code) and changes frequently enough where caching won&#8217;t help much, then &lt;a href=&quot;http://en.wikipedia.org/wiki/Denormalization&quot;&gt;denormalizing&lt;/a&gt; the attribute may be useful.&lt;/p&gt;


	&lt;p&gt;Let&#8217;s say you are calculating a list of top scores of participants in a series of games. One way to do it is&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Player&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;).each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |player|&lt;tt&gt;
&lt;/tt&gt;  puts player.games.sum{ |game| game.score }&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;If you only have a handful of players and games in the system, you&#8217;re fine. But increase it 10-fold and your nice &#8220;top scores&#8221; view begins to drag since a database call is being made to get each game&#8217;s score. Wouldn&#8217;t it be great if we could consolidate things to one roundtrip, like this:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Player&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:order&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;total_score DESC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |player|&lt;tt&gt;
&lt;/tt&gt;  puts player.total_score&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Well, you can, with a little bit of refactoring and applying a Ruby on Rails observer object. Observers allow you to attach behaviors to specific model events, or &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html&quot;&gt;callbacks&lt;/a&gt;. For example, you could write code that automatically logs an entry to a database table or sends out an email notification when a specific type of model is saved.&lt;/p&gt;


	&lt;p&gt;First, add the summary field &#8211; in this example, the &#8216;total_score&#8217; &#8211; to the desired table using a Rails migration script.&lt;/p&gt;


	&lt;p&gt;Then, create an observer object that will &#8220;watch&#8221; Game instances. Any time a Game&#8217;s score is updated, we will summarize the player&#8217;s total score in their record.&lt;/p&gt;


	&lt;p&gt;Creating the observer is easy, just use the generate script:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;script/generate observer game&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Inside the new GameObserver class, add this:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;GameObserver&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Observer&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;after_save&lt;/span&gt;(game)&lt;tt&gt;
&lt;/tt&gt;    player = game.player&lt;tt&gt;
&lt;/tt&gt;    player.update_attribute(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;total_score&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, player.total_score + game.score)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;But wait &#8211; you&#8217;re not done yet &#8211; you&#8217;ll also need to update your application&#8217;s environment.rb to activate the observer:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Rails&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Initializer&lt;/span&gt;.run &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |config|&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;#other config settings go here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  config.active_record.observers = &lt;span class=&quot;sy&quot;&gt;:game_observer&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then be sure you update any code still using the real-time calculated version of player&#8217;s scores and replace with player.total_score. If you&#8217;re trying to get the top 10 players, it&#8217;s as simple as&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Player&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:order&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;total_score DESC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:limit&lt;/span&gt; =&amp;gt; &lt;span class=&quot;i&quot;&gt;10&lt;/span&gt;)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h2&gt;Rolling Up the Sleeves&lt;/h2&gt;


	&lt;p&gt;In some cases, writing your own &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; can be the solution to squeezing out every millisecond of query performance. The trade-off, of course, is code maintenance. Every time you add a new field to your model, you&#8217;ll have to remember to update any hand-written queries. Everything you can do with &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; is abstracted in Active Record, so you don&#8217;t need to resort to it often. However, it can come in handy in reporting scenarios, where your query becomes complex, needing to display attributes from many objects, sometimes indirectly associated.&lt;/p&gt;


	&lt;p&gt;For example: display a list of emails for all active contacts associated with clients in the &#8216;West&#8217; sales region, who have open orders, containing items of category X with a status of &#8216;Backordered.&#8217;&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;co&quot;&gt;Contact&lt;/span&gt;.find_by_sql(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;select email from contacts co, clients cl, regions r, &lt;tt&gt;
&lt;/tt&gt;orders o, line_items li, products p, product_categories pc where &lt;tt&gt;
&lt;/tt&gt;co.client_id = cl.id and cl.region_id = r.id and o.client_id = cl.id &lt;tt&gt;
&lt;/tt&gt;and p.order_id = o.id and li.order_id = o.id and p.category_id = pc.id &lt;tt&gt;
&lt;/tt&gt;and r.region = 'West' and o.status = 'Open' and pc.name = 'X' and &lt;tt&gt;
&lt;/tt&gt;li.status = 'Backordered'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h2&gt;Tuning the Backend&lt;/h2&gt;


	&lt;p&gt;Adding a database index to a table, especially on columns that are frequently involved in joins, can boost performance as well. But be careful, as creating an index will improve read operations, but on the flip side, write operations will slow down. This article won&#8217;t go into the intricacies of database indexing, since this topic is already covered in detail &lt;a href=&quot;http://rip747.wordpress.com/2007/12/03/optmizing-your-database-with-indexes/&quot;&gt;elsewhere&lt;/a&gt;. However, Rails does makes things easy through migration scripts.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;AddGamesIndexes&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Migration&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.up&lt;tt&gt;
&lt;/tt&gt;    add_index &lt;span class=&quot;sy&quot;&gt;:games&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:player_id&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.down&lt;tt&gt;
&lt;/tt&gt;    remove_index &lt;span class=&quot;sy&quot;&gt;:games&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:player_id&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h2&gt;What Next&lt;/h2&gt;


	&lt;p&gt;We discussed some techniques that help you measure and refine performance in Ruby on Rails models before needing to consider other options, such as caching.&lt;/p&gt;


	&lt;p&gt;We also recommend keeping your Rails framework current and peeking into &lt;a href=&quot;http://wiki.rubyonrails.org/rails/pages/EdgeRails&quot;&gt;Edge Rails&lt;/a&gt; every now and then. Over the past 6 months, for instance, there has been a lot of activity focused on Active Record performance optimizations. &lt;a href=&quot;http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done&quot;&gt;Rails 2.0&lt;/a&gt; introduced query caching. This is an area which will continue to improve.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-05-29:4</id>
    <published>2008-05-29T01:00:00Z</published>
    <updated>2008-06-09T05:38:03Z</updated>
    <category term="All"/>
    <category term="News"/>
    <category term="case-studies"/>
    <category term="clients"/>
    <link href="http://www.webficient.com/2008/5/29/congratulations-to-sapphire-energy" rel="alternate" type="text/html"/>
    <title>Congratulations to Sapphire Energy</title>
<content type="html">
            &lt;p&gt;Today, &lt;a href=&quot;http://www.sapphireenergy.com&quot;&gt;Sapphire Energy&lt;/a&gt; launched their public Web site. We are happy to have been part of this effort,  which started at the beginning of the year and saw us join forces with &lt;a href=&quot;http://www.edelman.com&quot;&gt;Edelman&lt;/a&gt;, a global PR firm known for its great achievements and merits.&lt;/p&gt;


	&lt;p&gt;Sapphire Energy&#8217;s ground-breaking technology allows the production of gasoline from algae. This isn&#8217;t biodiesel either&#8212;it&#8217;s 91 octane gas that can be used in your car. In addition, Sapphire Energy does not need to use agricultural land as a source for its fuel. To learn more, check out Forbes&#8217; &lt;a href=&quot;http://www.forbes.com/technology/2008/05/28/alternative-fuels-biofuels-tech_sciences_cz_kad_0528fuels.html&quot;&gt;write-up&lt;/a&gt;.&lt;/p&gt;


	&lt;h2&gt;How Webficient Helped&lt;/h2&gt;


	&lt;p&gt;We were primarily responsible for the implementation of the &lt;a href=&quot;http://www.sapphireenergy.com&quot;&gt;Web site&lt;/a&gt; you see today. One of the highlights involved creating a content management system for site administrators and marketing folks, so that items such as press releases and news clips could be easily managed. Supporting Edelman, we ensured the final product looked as good as the designer&#8217;s prototypes and the content was accurate.&lt;/p&gt;


	&lt;h2&gt;Supporting Roles&lt;/h2&gt;


	&lt;p&gt;Behind the scenes, there&#8217;s a lot more involved with a project of this caliber. To preemptively block domain squatters from buying up variations of SapphireEnergy.com, we helped research and secure dozens of other domain names.&lt;/p&gt;


	&lt;p&gt;We were responsible for all technology decisions, such as planning the infrastructure powering the Web site.&lt;/p&gt;


	&lt;p&gt;Also, a critical aspect of the project was preparing for launch day and the waves of visitors that would arrive in response to coverage in the major news outlets. We setup monitoring systems to detect any potential problems. Prior to the launch, we simulated various scenarios of site usage to test limits. This gave us a working model for understanding what to do as usage increased. [Editor&#8217;s note, 6/8/08: we&#8217;re happy to report that the site has been running since launch day without any downtime.]&lt;/p&gt;


	&lt;h2&gt;Technology&lt;/h2&gt;


	&lt;p&gt;We used the Ruby on Rails application framework to build what you see today. There are many reasons we love using Rails again and again in our projects, for clients and internal tools. We&#8217;ll elaborate on some of reasons in a more technical write-up in the near future.&lt;/p&gt;


	&lt;h2&gt;Thanks&lt;/h2&gt;


	&lt;p&gt;Webficient would like to thank its partners and vendors for contributing to the success of the overall project, launch day, and beyond.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Sapphire Energy&#8217;s design is the brilliant production of &lt;a href=&quot;http://www.mobiletechunit.com/design/&quot;&gt;Paula Wood&lt;/a&gt;. This was our first opportunity to work with Paula, and we hope to do so again in the future.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;https://manage.slicehost.com/customers/new?referrer=1616112070&quot;&gt;Slicehost.com&lt;/a&gt;. Straightforward. Affordable. Awesome Web hosting. No problems to report since we started using their services earlier this year. We continue to recommend their services to clients and colleagues.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;https://fiveruns.com&quot;&gt;Fiveruns&lt;/a&gt;, and their server and application monitoring service, is one of our recent favorites. Their service is easy to setup and provides valuable metrics that system administrators will eat up. We were able to use Fiveruns to provide real-time numbers to our client. It&#8217;s a great complement to Google Analytics.&lt;/li&gt;
	&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-05-26:3</id>
    <published>2008-05-26T17:00:00Z</published>
    <updated>2008-05-30T22:54:38Z</updated>
    <category term="All"/>
    <category term="News"/>
    <category term="team"/>
    <link href="http://www.webficient.com/2008/5/26/who-is-webficient" rel="alternate" type="text/html"/>
    <title>Who is Webficient?</title>
<content type="html">
            &lt;p&gt;We are a group of IT professionals who love working on complex problems. We&#8217;ll be featuring some of our work here as case studies.  We&#8217;ll be sharing our insights through blog posts, code snippets, and screenshots. We hope we can spark some interesting conversations. Thus, one goal for Webficient is to share a repository of knowledge that can be applied to your projects.&lt;/p&gt;


	&lt;p&gt;The other aspect, of course, is the business end. We&#8217;ve recently relaunched this site to be more than just a blog&#8230; we&#8217;re hoping to connect with new businesses and partners who want to work on big ideas. We&#8217;re also here to help you with the small ones too. :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2008-02-04:7</id>
    <published>2008-02-04T04:58:00Z</published>
    <updated>2008-06-11T05:01:50Z</updated>
    <category term="All"/>
    <category term="Solutions"/>
    <category term="patches"/>
    <category term="rubyonrails"/>
    <link href="http://www.webficient.com/2008/2/4/fixing-mongrels-page-caching" rel="alternate" type="text/html"/>
    <title>Fixing Mongrel's Page Caching</title>
<content type="html">
            &lt;p&gt;While playing around with Rails page caching, we discovered a peculiar quirk. Any pages set to be cached are saved as static &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; files, but Mongrel doesn&#8217;t seem to be able to find them and continues to process subsequent requests dynamically. This only happens though if you change the Rails&#8217; page cache directory in your application configuration. Upon digging further, here&#8217;s what we uncovered.&lt;/p&gt;


	&lt;p&gt;By default, Rails will cache files in /public, and this works fine if you enable caching in your development environment.  However, with a different cache location, such as&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;config.action_controller.page_cache_directory = &lt;span class=&quot;co&quot;&gt;RAILS_ROOT&lt;/span&gt; + &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/tmp/cache&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;things no longer work as expected. It turns out that Mongrel completely ignores this setting when looking for cached content. Furthermore, Mongrel&#8217;s directory handler assumes that files will always be located under /public.&lt;/p&gt;


	&lt;p&gt;If you want to patch this up on your local machine, just apply &lt;a href=&quot;http://rubyforge.org/tracker/index.php?func=detail&amp;amp;#38;aid=17713&amp;amp;#38;group_id=1306&amp;amp;#38;atid=5147&quot;&gt;this Mongrel patch&lt;/a&gt;.&lt;/p&gt;


	&lt;h2&gt;Page Caching Tips&lt;/h2&gt;


	&lt;p&gt;Here&#8217;s some useful info if you&#8217;re implementing page caching in Ruby on Rails.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Using Mongrel to read cached pages is fine for development and &lt;span class=&quot;caps&quot;&gt;POC&lt;/span&gt;&#8217;s but your best bet is to put this responsibility into the hands of an &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; front-end such as Apache or Nginx.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;If you want to cache every view in a controller, instead of adding &#8220;caches_page&#8221; for each action, just add this line near the top of your controller:&lt;/li&gt;
	&lt;/ul&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;after_filter { |c| c.cache_page}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;ul&gt;
	&lt;li&gt;If you&#8217;re caching pages in a password protected part of your site, a relatively painless solution is to configure Apache or Nginx to read an htpasswd file and handle authentication on the front-end. Alternately, you could use Rails 2.0&#8217;s basic authentication as part of a before_filter but this would only work with fragment caching (since full page caching ignores any controller filters completely).&lt;/li&gt;
	&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2007-11-16:5</id>
    <published>2007-11-16T22:48:00Z</published>
    <updated>2008-05-30T21:39:17Z</updated>
    <category term="All"/>
    <category term="Working Faster"/>
    <category term="tips"/>
    <link href="http://www.webficient.com/2007/11/16/mac-and-ssh-keys" rel="alternate" type="text/html"/>
    <title>Mac and SSH Keys</title>
<content type="html">
            &lt;p&gt;If you&#8217;re Web programming on a Mac and are moving data around using the &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; network protocol, it&#8217;s a good idea to setup an &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; key on the destination server. You&#8217;ll speed up your workflow by not having to enter a password each time.&lt;/p&gt;


	&lt;p&gt;Setting up a key is pretty easy. First create the key on your machine using Terminal:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ssh-keygen -t rsa -f ~/.ssh/id_rsa -C &amp;quot;me@mymachine&amp;quot;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then, run this command to create a special directory on your server that is needed for &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; key authentication. The username must be the one you&#8217;re going to use for &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt;, Capistrano, etc. You can have a key for each user, e.g. deploy.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ssh username@subdomain.host.com 'mkdir ~/.ssh;chmod 700 ~/.ssh'&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then deploy the key to your server using the username you want to associate with the key:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;scp ~/.ssh/id_rsa.pub username@subdomain.host.com:~/.ssh/authorized_keys2&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then update the permissions on the server for the authorized_keys file you just created:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ssh username@subdomain.host.com 'chmod 600 ~/.ssh/authorized_keys2'&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Note: the above commands assume your destination machine is using the more secure, &lt;span class=&quot;caps&quot;&gt;SSH2&lt;/span&gt;. For &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt;, just change &#8216;authorized_keys2&#8217; to &#8216;authorized_keys&#8217; above.&lt;/p&gt;


	&lt;p&gt;You&#8217;re done. To test everything is working, you can simply ssh username@host via Terminal. If you&#8217;re still getting a password prompt, then you may have missed something.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2007-11-16:8</id>
    <published>2007-11-16T05:46:00Z</published>
    <updated>2008-05-30T22:51:04Z</updated>
    <category term="All"/>
    <category term="Solutions"/>
    <category term="tips"/>
    <link href="http://www.webficient.com/2007/11/16/installing-the-rmagick-gem-on-mac-osx-leopard" rel="alternate" type="text/html"/>
    <title>Installing the RMagick gem on Mac OSX Leopard</title>
<content type="html">
            &lt;p&gt;If you&#8217;re having problems installing the RMagick gem on Leopard and you&#8217;re not using MacPorts, this info may help.&lt;/p&gt;


	&lt;p&gt;First, ensure you have the latest version of the &lt;span class=&quot;caps&quot;&gt;UNIX&lt;/span&gt; developer tools from your Leopard CD. Otherwise, you&#8217;ll see errors like&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ERROR: Failed to build gem native extension.&lt;tt&gt;
&lt;/tt&gt;configure: error: C compiler cannot create executables&lt;tt&gt;
&lt;/tt&gt;See `config.log' for more details.&lt;tt&gt;
&lt;/tt&gt;RMagick configuration failed with status 77.&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then, download the RMagick &lt;span class=&quot;caps&quot;&gt;OSX&lt;/span&gt; Installer &lt;a href=&quot;http://rubyforge.org/projects/rmagick/&quot;&gt;available here&lt;/a&gt;. It&#8217;s a Ruby script which retrieves all of the required dependencies and then builds them and RMagick.&lt;/p&gt;


	&lt;p&gt;Finally, install the gem:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;sudo gem install rmagick&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          </content>  </entry>
  <entry xml:base="http://www.webficient.com/">
    <author>
      <name>webficient</name>
    </author>
    <id>tag:www.webficient.com,2007-08-20:6</id>
    <published>2007-08-20T22:33:00Z</published>
    <updated>2008-05-30T21:55:45Z</updated>
    <category term="All"/>
    <category term="Solutions"/>
    <link href="http://www.webficient.com/2007/8/20/how-to-configure-swiftiply-with-nginx" rel="alternate" type="text/html"/>
    <title>How to Configure Swiftiply with Nginx</title>
<content type="html">
            &lt;p&gt;Swiftiply is a proxying solution which boosts the performance of Ruby on Rails and Merb apps. One configuration allows you to use Swiftiply as an &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; proxy, leveraging what are known as &#8220;Swiftiplied&#8221; Mongrels. These patched Mongrels become clients of the Swiftiply server and maintain a persistent connection, which is a reversal of the usual proxying solution (think Pound, Squid, etc.).&lt;/p&gt;


	&lt;p&gt;Nginx is a lightweight, fast &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; server, which is gaining popularity. Nginx is setup as a reverse proxy to Swiftiply, which in turn has a direct connection to multiple Mongrel processes.&lt;/p&gt;


	&lt;p&gt;So when an &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; request comes in, the pipeline looks like this&#8230;&lt;/p&gt;


	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; request -&amp;gt; Nginx -&amp;gt; Swiftiply -&amp;gt; Mongrels&lt;/p&gt;


	&lt;p&gt;To successfully make Nginx and Swiftiply play nicely with one another, the configuration is fairly straightforward.&lt;/p&gt;


	&lt;p&gt;In nginx.conf, the cluster consists of &lt;span class=&quot;caps&quot;&gt;ONE&lt;/span&gt; server entry:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;upstream mongrel_test_cluster {&lt;tt&gt;
&lt;/tt&gt;  server 127.0.0.1:4000;&lt;tt&gt;
&lt;/tt&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;This may appear strange at first glance but really, what you&#8217;re telling Nginx is to proxy all requests to the same port being listened on by Swiftiply, which in turn, communicates with the Mongrels.&lt;/p&gt;


	&lt;p&gt;In swiftiply.yml:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;cluster_address: 127.0.0.1&lt;tt&gt;
&lt;/tt&gt;cluster_port: 4000&lt;tt&gt;
&lt;/tt&gt;daemonize: true&lt;tt&gt;
&lt;/tt&gt;epoll: true&lt;tt&gt;
&lt;/tt&gt;epoll_descriptors: 8192&lt;tt&gt;
&lt;/tt&gt;map:&lt;tt&gt;
&lt;/tt&gt;- incoming: localhost&lt;tt&gt;
&lt;/tt&gt;outgoing: 127.0.0.1:5000&lt;tt&gt;
&lt;/tt&gt;default: true&lt;tt&gt;
&lt;/tt&gt;docroot: /usr/local/httpd/testapp&lt;tt&gt;
&lt;/tt&gt;redeployable: true&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Swiftiply is listening on port 4000 and passing requests to port 5000 (to the &#8220;Swiftiplied&#8221; Mongrels).&lt;/p&gt;


	&lt;p&gt;To transform your Mongrel into a Swiftiplied Mongrel, just add the following line to your app&#8217;s config file:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require 'swiftcore/swiftiplied_mongrel'&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then, it&#8217;s as simple as firing up your Swiftiplied Mongrels and the Swiftiply server (both are covered in more detail in the &lt;a href=&quot;http://swiftiply.swiftcore.org/documentation.html&quot;&gt;Swiftcore docs&lt;/a&gt;), and Nginx.&lt;/p&gt;


	&lt;p&gt;The other Swiftiply configuration, using &#8220;Evented&#8221; Mongrels, is much simpler and does not use the Swiftiply server.&lt;/p&gt;


	&lt;p&gt;Just add this include to your Web application&#8217;s configuration file:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require 'swiftcore/swiftiplied_mongrel'&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;and configure Nginx as you would with a standard set of Mongrels.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;upstream mongrel_test_cluster {&lt;tt&gt;
&lt;/tt&gt;  server 127.0.0.1:4000;&lt;tt&gt;
&lt;/tt&gt;  server 127.0.0.1:4001;&lt;tt&gt;
&lt;/tt&gt;  server 127.0.0.1:4002;&lt;tt&gt;
&lt;/tt&gt;  server 127.0.0.1:4003;&lt;tt&gt;
&lt;/tt&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Then start up your Mongrels as described in the Swiftiply docs, and you&#8217;re done.&lt;/p&gt;
          </content>  </entry>
</feed>
