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

<channel>
	<title>Phusion Corporate Blog &#187; Ruby on Rails</title>
	<atom:link href="http://blog.phusion.nl/category/ruby-on-rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.phusion.nl</link>
	<description></description>
	<lastBuildDate>Mon, 06 Sep 2010 12:01:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Does Rails Performance Need an Overhaul?</title>
		<link>http://blog.phusion.nl/2010/06/09/does-rails-performance-need-an-overhaul/</link>
		<comments>http://blog.phusion.nl/2010/06/09/does-rails-performance-need-an-overhaul/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 19:56:20 +0000</pubDate>
		<dc:creator>Hongli Lai</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=635</guid>
		<description><![CDATA[Igvita.com has recently published the article Rails Performance Needs an Overhaul. Rails performance&#8230; no, Ruby performance&#8230; no Rails scalability&#8230; well something is being criticized here. From my experience, talking about scalability and performance can be a bit confusing because the terms can mean different things to different people and/or in different situations, yet the meanings [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.igvita.com/">Igvita.com</a> has recently published the article <a href="http://www.igvita.com/2010/06/07/rails-performance-needs-an-overhaul/">Rails Performance Needs an Overhaul</a>. Rails performance&#8230; no, Ruby performance&#8230; no Rails scalability&#8230; well <b>something</b> is being criticized here. From my experience, talking about scalability and performance can be a bit confusing because the terms can mean different things to different people and/or in different situations, yet the meanings are used interchangeably all the time. In this post I will take a closer look at Igvita&#8217;s article.</p>
<h2>Performance vs scalability</h2>
<p>Let us first define performance and scalability. I define <b>performance</b> as throughput; number of requests per second. I define <b>scalability</b> as the amount of users a system can concurrently handle. There is a correlation between performance and scalability. Higher performance means each request takes less time, and so is more scalable, right? Sometimes yes, but not necessarily. It is entirely possible for a system to be scalable, yet manages to have a lower throughput than a system that&#8217;s not as scalable, or for a system to be uber-fast yet not very scalable. Throughout this blog post I will show several examples that highlight the difference.</p>
<p>&#8220;Scalability&#8221; is an extremely loaded word and people often confuse it with &#8220;being able to handle tons and tons of traffic&#8221;. Let&#8217;s use a different term that better reflects what Igvita&#8217;s actually criticizing: <b>concurrency</b>. Igvita claims that concurrency in Ruby is pathetic while referring to database drivers, Ruby application servers, etc. Some practical examples that demonstrate what he means are as follows.</p>
<h2>Limited concurrency at the app server level</h2>
<p>Mongrel, Phusion Passenger and Unicorn all use a &#8220;traditional&#8221; multi-process model in which multiple Ruby processes are spawned, each process handling a single request per second. Thus, concurrency is (assuming that the load balancer has infinite concurrency) limited by the number of Ruby processes: having 5 processes allow you to handle 5 users concurrently.</p>
<p>Threaded servers, where the server spawns multiple threads, each handling 1 connection concurrently, allow more concurrency because because it&#8217;s possible to spawn a whole lot more threads than processes. In the context of Ruby, each Ruby process needs to load its own copy of the application code and other resources, so memory increases very quickly as you spawn additional processes. Phusion Passenger with Ruby Enterprise Edition solves this problem somewhat by using copy-on-write optimizations which save memory, so you can spawn a bit more processes, but not significantly (as in 10x) more. In contrast, a multi-threaded app server does not need as much memory because all threads share application code with each other so you can comfortably spawn tens or hundreds of threads. At least, this is the theory. I will later explain why this does not necessarily hold for Ruby.</p>
<p>When it comes to performance however, there&#8217;s no difference between processes and threads. If you compare a well-written multi-threaded app server with 5 threads to a well-written multi-process app server with 5 processes, you won&#8217;t find either being more performant than the other. Context switch overhead between processes and threads are roughly the same. Each process can use a different CPU core, as can each thread, so there&#8217;s no difference in multi-core utilization either. This reflects back on the difference between scalability/concurrency and performance.</p>
<p>Multi-process Rails app servers have a concurrency level that can be counted with a single hand, or if you have very beefy hardware, a concurrency level in the range of a couple of tens, thanks to the fact that Rails needs about 25 MB per process. Multi-threaded Rails app servers can in theory spawn a couple of hundred of threads. After that it&#8217;s also game over: an operating system thread needs a couple MB of stack space, so after a couple hundreds of threads you&#8217;ll run out of <b>virtual memory address</b> on 32-bit systems even if you don&#8217;t actually use that much memory.</p>
<p>There is another class of servers, the evented ones. These servers are actually single-threaded, but they use a <a href="http://en.wikipedia.org/wiki/Reactor_pattern">reactor style I/O dispatch architecture</a> for handling I/O concurrency. Examples include Node.js, Thin (built on EventMachine) and Tornado. These servers can easily have a concurrency level of a couple of thousand. But due to their single-threaded nature they cannot effectively utilize multiple CPU cores, so you need to run a couple of processes, one per CPU core, to fully utilize your CPU.</p>
<h2>The limits of Ruby threads</h2>
<p>Ruby 1.8 uses userspace threads, not operating system threads. This means that Ruby 1.8 can only utilize a single CPU core no matter how many Ruby threads you create. This is why one typically needs multiple Ruby processes to fully utilize one&#8217;s CPU cores. Ruby 1.9 finally uses operating system threads, but it has a global interpreter lock, which means that each time a Ruby 1.9 thread is running it will prevent other Ruby threads from running, effectively making it the same multicore-wise as 1.8. This is also explained in an earlier Igvita article, <a href="http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/">Concurrency is a Myth in Ruby</a>.</p>
<p>On the bright side, not all is bad. Ruby 1.8 internally uses non-blocking I/O while Ruby 1.9 unlocks the global interpreter lock while doing I/O. So if one Ruby thread is blocked on I/O, another Ruby thread can continue execution. Likewise, Ruby is smart enough to cause things like sleep() and even waitpid() to preempt to other threads.</p>
<p>On the dark side however, Ruby internally uses the select() system call for multiplexing I/O. select() can only handle 1024 file descriptors on most systems so Ruby cannot handle more than this number of sockets per Ruby process, even if you are somehow able to spawn thousands of Ruby threads. EventMachine works around this problem by bypassing Ruby&#8217;s I/O code completely.</p>
<h2>Naive native extensions and third party libraries</h2>
<p>So just run a couple of multi-threaded Ruby processes, one process per core and multiple threads per process, and all is fine and we should be able to have a concurrency level of up to a couple hundred, right? Well not quite, there are a number of issues hindering this approach:</p>
<ul>
<li>Some third party libraries and Rails plugins are not thread-safe. Some aren&#8217;t even <a href="http://doc.trolltech.com/3.3/threads.html#4">reentrant</a>. For example Rails &lt; 2.2 suffered from this problem. The app itself might not be thread-safe.</li>
<li>Although Ruby is smart enough not to let I/O block all threads, the same cannot be said of all native extensions. The MySQL extension is the most infamous example: when executing queries, other threads cannot run.</li>
</ul>
<p>Mongrel is actually multi-threaded but in practice everybody uses in multi-process mode (mongrel_cluster) exactly because of these problems. It is also the reason why Phusion Passenger has also gone the multi-process route.</p>
<p>And even though Thin is evented, a typical Ruby web application running on Thin cannot handle thousands of concurrent users. This is because evented servers typically require a special evented programming style, such as the one seen in Node.js and EventMachine. A Ruby web app that is written in an evented style running on Thin can definitely handle a large number of concurrent users.</p>
<h2>When is limited application server concurrency actually a problem?</h2>
<p>Igvita is clearly disappointed at all all the issues that hinder Ruby web apps from achieving high concurrency. For many web applications I would however argue that limited concurrency is not a problem.</p>
<ul>
<li>Web applications that are slow, as in CPU-heavy, max out CPU resources pretty quickly so increasing concurrency won&#8217;t help you.</li>
<li>Web applications that are fast are typically quick enough at handling the load so that even large number of users won&#8217;t notice the limited concurrency of the server.</li>
</ul>
<p>Having a concurrency of 5 does not mean not mean that the app server can only handle 5 requests per second; it&#8217;s not hard to serve hundreds of requests per second with only a couple of single-threaded processes.</p>
<p>The problem becomes most evident for web applications that have to wait a lot for I/O (besides its own HTTP request/response cycle). Examples include:</p>
<ol>
<li>Apps that have to spend a lot of time waiting on the database.</li>
<li>Apps that perform a lot of external HTTP calls that respond slowly.</li>
<li>Chat apps. These apps typically have thousands of users, most of them doing nothing most of the time, but they all require a connection (unless your app uses polling, but that&#8217;s a whole different discussion).</li>
</ol>
<p>We at Phusion have developed a number of web applications for clients that fall in the second category, the most recent one being a Hyves gadget. <a href="http://www.hyves.nl/">Hyves</a> is the most popular social network in the Netherlands and they get thousands of concurrent visitors during the day. The gadget that we&#8217;ve developed has to query external HTTP servers very often, and these servers can take 10 seconds to respond in extreme cases. The servers are running Phusion Passenger with maybe a couple tens of processes. If every request to our gadget also causes us to wait 10 seconds for the external HTTP call then we&#8217;d soon run out of concurrency.</p>
<p>But even suppose that our app and Phusion Passenger can have a concurrency level of a couple of thousand, all of those visitors will still have to wait 10 seconds for the external HTTP calls, which is obviously unacceptable. This is another example that illustrates the difference between scalability and performance. We had solved this problem by aggressively caching the results of the HTTP calls, minimizing the number of external HTTP calls that are necessary. The result is that even though the application&#8217;s concurrency is fairly limited, it can still comfortably serve many concurrent users with a reasonable response time.</p>
<p>This anecdote should explain why I believe that web apps can get very far despite having a limited concurrency level. That said, as Internet usage continues to increase and websites get more and more users, we may at some time come to a point where much a larger concurrency level is required than most of our current Ruby tools allow us to (assuming server capacity doesn&#8217;t scale quickly enough).</p>
<h2>What was Igvita.com criticizing?</h2>
<p>Igvita.com does not appear to be criticizing Ruby or Rails for being slow. It doesn&#8217;t even appear to be criticizing the lack of Ruby tools for achieving high concurrency. It appears to be criticizing these things:</p>
<ul>
<li>Rails and most Ruby web application servers don&#8217;t allow high concurrency by default.</li>
<li>Many database drivers and libraries hinder concurrency.</li>
<li>Although alternatives exist that allow concurrency, you have to go out of your way to find them.</li>
<li>There appears to be little motivation in the Ruby community for making the entire stack of web frame work + web app server + database drivers etc scalable by default.</li>
</ul>
<p>This is in contrast to Node.js where everything is scalable by default.</p>
<p>Do I understand Igvita&#8217;s frustration? Absolutely. Do I agree with it? Not entirely. The same thing that makes Node.js so scalable is also what makes it relatively hard to program for. Node.js enforces a callback style of programming and this can eventually make your code look a lot more complicated and harder to read than regular code that uses blocking calls. Furthermore, Node.js is relatively young &#8211; of course you won&#8217;t find any Node.js libraries that don&#8217;t scale! But if people ever use Node.js for things other than high-concurrency servers apps, then non-scalable libraries will at some time pop up. And then you will have to look harder to avoid these libraries. There is no silver bullet.</p>
<p>That said, all would be well if at least the preferred default stack can handle high concurrency by default. This means e.g. fixing the MySQL extension and have the fix published by upstream. The mysqlplus extension fixes this but for some reason their changes aren&#8217;t accepted and published by the original author, and so people end up with a multi-thread-killing database driver by default.</p>
<h2>Is Node.js innovative? Is Ruby lacking innovation?</h2>
<p>A minor gripe that I have with the article is that Igvita calls Node.js innovative while seemingly implying that the Ruby stack isn&#8217;t innovating. Evented servers like Node.js actually have been around for years and the evented pattern is well-known long before Ruby or Javascript have become popular. Thin is also evented and predates Node.js by several years. Thin and EventMachine also allow Node.js-style evented programming. The only innovation that Node.js brings, in my opinion, is the fact that it&#8217;s Javascript. The other &#8220;innovation&#8221; is the lack of non-scalable libraries.</p>
<h2>Conclusion</h2>
<p>Igvita appears to be criticizing something other than Rails performance, as his article&#8217;s title would imply.</p>
<p>I don&#8217;t think the concurrency levels that the Rails stack provides by default is that bad in practice. But as a fellow programmer, it does intuitively bother me that our laptops, which are a million times more powerful than supercomputers from two decades ago, cannot comfortably handle a couple of thousand concurrent users. We can definitely work towards something better, but in the mean time let&#8217;s not forget that the current stack is more than capable of Getting Work Done(tm).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2010/06/09/does-rails-performance-need-an-overhaul/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Announcing EncryptedCookieStore plugin for Rails 2.3</title>
		<link>http://blog.phusion.nl/2010/04/13/announcing-encryptedcookiestore-plugin-for-rails-2-3/</link>
		<comments>http://blog.phusion.nl/2010/04/13/announcing-encryptedcookiestore-plugin-for-rails-2-3/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 21:46:28 +0000</pubDate>
		<dc:creator>Hongli Lai</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=599</guid>
		<description><![CDATA[EncryptedCookieStore is similar to Ruby on Rails&#8217;s CookieStore (it saves session data in a cookie), but it uses encryption so that people can&#8217;t read what&#8217;s in the session data. This makes it possible to store sensitive data in the session. EncryptedCookieStore is written for Rails 2.3. Other versions of Rails have not been tested. Note: [...]]]></description>
			<content:encoded><![CDATA[<p>EncryptedCookieStore is similar to Ruby on Rails&#8217;s CookieStore (it saves session data in a cookie), but it uses encryption so that people can&#8217;t read what&#8217;s in the session data. This makes it possible to store sensitive data in the session.</p>
<p>EncryptedCookieStore is written for Rails 2.3. Other versions of Rails have not been tested.</p>
<p><b>Note</b>: This is <i>not</i> ThinkRelevance&#8217;s EncryptedCookieStore. In the Rails 2.0 days they wrote an EncryptedCookieStore, but it seems their repository had gone defunct and their source code lost. This EncryptedCookieStore is written from scratch by Phusion.</p>
<p>Source code at <a href="http://github.com/FooBarWidget/encrypted_cookie_store">http://github.com/FooBarWidget/encrypted_cookie_store</a></p>
<h2>Installation and usage</h2>
<p>First, install it:</p>
<pre>./script/plugin install git://github.com/FooBarWidget/encrypted_cookie_store.git</pre>
<p>Then edit <tt>config/initializers/session_store.rb</tt> and set your session store to EncryptedCookieStore:</p>
<pre>ActionController::Base.session_store = EncryptedCookieStore</pre>
<p>You need to set a few session options before EncryptedCookieStore is usable. You must set all options that CookieStore needs, plus an encryption key that EncryptedCookieStore needs. In <tt>session_store.rb</tt>:</p>
<pre lang="ruby">
ActionController::Base.session = {
        # CookieStore options...
        :key            => '_session',     # Name of the cookie which contains the session data.
        :secret         => 'b4589cc9...',  # A secret string used to generate the checksum for
                                           # the session data. Must be longer than 64 characters
                                           # and be completely random.

        # EncryptedCookieStore options...
        :encryption_key => 'c306779f3...', # The encryption key. See below for notes.
}</pre>
<p>The encryption key <b>must</b> be a hexadecimal string of exactly 32 bytes. It should be entirely random, because otherwise it can make the encryption weak.</p>
<p>You can generate a new encryption key by running <tt>rake secret:encryption_key</tt>. This command will output a random encryption key that you can then copy and paste into your environment.rb.</p>
<h2>Operational details</h2>
<p>Upon generating cookie data, EncryptedCookieStore generates a new, random initialization vector for encrypting the session data. This initialization vector is then encrypted with 128-bit AES in ECB mode. The session data is first protected with an HMAC to prevent tampering. The session data, along with the HMAC, are then encrypted using 256-bit AES in CFB mode with the generated initialization vector. This encrypted session data + HMAC are then stored, along with the encrypted initialization vector, into the cookie.</p>
<p>Upon unmarshalling the cookie data, EncryptedCookieStore decrypts the encrypted initialization vector and use that to decrypt the encrypted session data + HMAC. The decrypted session data is then verified against the HMAC.</p>
<p>The reason why HMAC verification occurs after decryption instead of before decryption is because we want to be able to detect changes to the encryption key and changes to the HMAC secret key, as well as migrations from CookieStore. Verifying after decryption allows us to automatically invalidate such old session cookies.</p>
<p>EncryptedCookieStore is quite fast: it is able to marshal and unmarshal a simple session object 5000 times in 8.7 seconds on a MacBook Pro with a 2.4 Ghz Intel Core 2 Duo (in battery mode). This is about 0.174 ms per marshal+unmarshal action. See <tt>rake benchmark</tt> in the EncryptedCookieStore sources for details.</p>
<h2>EncryptedCookieStore vs other session stores</h2>
<p>EncryptedCookieStore inherits all the benefits of CookieStore:</p>
<ul>
<li>It works out of the box without the need to setup a seperate data store (e.g. database table, daemon, etc).</li>
<li>It does not require any maintenance. Old, stale sessions do not need to be manually cleaned up, as is the case with PStore and ActiveRecordStore.</li>
<li>Compared to MemCacheStore, EncryptedCookieStore can &#8220;hold&#8221; an infinite number of sessions at any time.</li>
<li>It can be scaled across multiple servers without any additional setup.</li>
<li>It is fast.</li>
<li>It is more secure than CookieStore because it allows you to store sensitive data in the session.</li>
</ul>
<p>There are of course drawbacks as well:</p>
<ul>
<li>It is prone to session replay attacks. These kind of attacks are explained in the <a href="http://guides.rubyonrails.org/security.html#session-storage">Ruby on Rails Security Guide</a>. Therefore you should never store anything along the lines of <tt>is_admin</tt> in the session.</li>
<li>You can store at most a little less than 4 KB of data in the session because that&#8217;s the size limit of a cookie. &#8220;A little less&#8221; because EncryptedCookieStore also stores a small amount of bookkeeping data in the cookie.</li>
<li>Although encryption makes it more secure than CookieStore, there&#8217;s still a chance that a bug in EncryptedCookieStore renders it insecure. We welcome everyone to audit this code. There&#8217;s also a chance that weaknesses in AES are found in the near future which render it insecure. If you are storing *really* sensitive information in the session, e.g. social security numbers, or plans for world domination, then you should consider using ActiveRecordStore or some other server-side store.</li>
</ul>
<h2>JRuby: Illegal Key Size error</h2>
<p>If you get this error (and your code works with MRI)&#8230;</p>
<pre>    Illegal key size

    [...]/vendor/plugins/encrypted_cookie_store/lib/encrypted_cookie_store.rb:62:in `marshal'</pre>
<p>&#8230;then it probably means you don&#8217;t have the &#8220;unlimited strength&#8221; policy files installed for your JVM. <a href="http://www.ngs.ac.uk/tools/jcepolicyfiles">Download and install them.</a> You probably have the &#8220;strong&#8221; version if they are already there.</p>
<p>As a workaround, you can change the cipher type from 256-bit AES to 128-bit by<br />
inserting the following in <tt>config/initializer/session_store.rb</tt>:</p>
<pre>EncryptedCookieStore.data_cipher_type = 'aes-128-cfb'.freeze  # was 256</pre>
<p>Please note that after changing to 128-bit AES, EncryptedCookieStore still requires a 32 bytes hexadecimal encryption key, although only half of the key is actually used.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2010/04/13/announcing-encryptedcookiestore-plugin-for-rails-2-3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>default_value_for Rails plugin: declaratively define default values for ActiveRecord models</title>
		<link>http://blog.phusion.nl/2008/10/03/47/</link>
		<comments>http://blog.phusion.nl/2008/10/03/47/#comments</comments>
		<pubDate>Fri, 03 Oct 2008 15:13:31 +0000</pubDate>
		<dc:creator>Hongli Lai</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=47</guid>
		<description><![CDATA[Introduction The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner. For example: class User &#60; ActiveRecord::Base default_value_for :name, "(no name)" default_value_for :last_seen do Time.now end end u = User.new u.name # =&#62; "(no name)" u.last_seen # =&#62; Mon Sep 22 17:28:38 +0200 2008 We at Phusion use it [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner. For example:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :name, "(no name)"
  default_value_for :last_seen do
    Time.now
  end
end

u = User.new
u.name       # =&gt; "(no name)"
u.last_seen  # =&gt; Mon Sep 22 17:28:38 +0200 2008</pre>
<p>We at Phusion use it for generating UUIDs for models.</p>
<p><b>Note</b>: critics might be interested in the &#8220;When (not) to use default_value_for?&#8221; section. Please read on.</p>
<h2>Installation</h2>
<p>Install with:</p>
<pre>./script/plugin install git://github.com/FooBarWidget/default_value_for.git</pre>
<p>See also <a href="http://agilewebdevelopment.com/plugins/default_value_for">the AgileWebDevelopment Plugins</a> entry.</p>
<p>If you like this plugin, then please <a href="http://www.modrails.com/enterprise.html">consider donating</a> and/or recommending us:</p>
<table class="wwr">
<tr>
<td>
<a href="http://www.workingwithrails.com/person/11402-hongli-lai"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Hongli Lai</a>
</td>
<td>
<a href="http://www.workingwithrails.com/person/12429-ninh-bui"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Ninh Bui</a>
</td>
</tr>
</table>
<h2>The default_value_for method</h2>
<p>The <code>default_value_for</code> method is available in all ActiveRecord model classes.</p>
<p>The first argument is the name of the attribute for which a default value should be set. This may either be a Symbol or a String.</p>
<p>The default value itself may either be passed as the second argument:</p>
<pre>default_value_for :age, 20</pre>
<p>&#8230;or it may be passed as the return value of a block:</p>
<pre>default_value_for :age do
  if today_is_sunday?
    20
  else
    30
  end
end</pre>
<p>If you pass a value argument, then the default value is static and never changes. However, if you pass a block, then the default value is retrieved by calling the block. This block is called not once, but every time a new record is instantiated and default values need to be filled in.</p>
<p>The latter form is especially useful if your model has a UUID column. One can generate a new, random UUID for every newly instantiated record:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :uuid do
    UuidGenerator.new.generate_uuid
  end
end

User.new.uuid  # =&gt; "51d6d6846f1d1b5c9a...."
User.new.uuid  # =&gt; "ede292289e3484cb88...."</pre>
<p>Note that record is passed to the block as an argument, in case you need it for whatever reason:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :uuid do |x|
    x   # &lt;--- a User object
    UuidGenerator.new.generate_uuid
  end
end</pre>
<h2>Rules</h2>
<h3>Instantiation of new record</h3>
<p>Upon instantiating a new record, the declared default values are filled into the record. You&#8217;ve already seen this in the above examples.</p>
<h3>Retrieval of existing record</h3>
<p>Upon retrieving an existing record, the declared default values are <em>not</em> filled into the record. Consider the example with the UUID:</p>
<pre>user = User.create
user.uuid   # =&gt; "529c91b8bbd3e..."

user = User.find(user.id)
# UUID remains unchanged because it's retrieved from the database!
user.uuid   # =&gt; "529c91b8bbd3e..."</pre>
<h3>Mass-assignment</h3>
<p>If a certain attribute is being assigned via the model constructor&#8217;s mass-assignment argument, that the default value for that attribute will <em>not</em> be filled in:</p>
<pre>user = User.new(:uuid =&gt; "hello")
user.uuid   # =&gt; "hello"</pre>
<p>However, if that attribute is protected by <code>attr_protected</code> or <code>attr_accessible</code>, then it will be filled in:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :name, 'Joe'
  attr_protected :name
end

user = User.new(:name =&gt; "Jane")
user.name   # =&gt; "Joe"</pre>
<h3>Inheritance</h3>
<p>Inheritance works as expected. All default values are inherited by the child<br />
class:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :name, 'Joe'
end

class SuperUser &lt; User
end

SuperUser.new.name   # =&gt; "Joe"</pre>
<h3>Attributes that aren&#8217;t database columns</h3>
<p><code>default_value_for</code> also works with attributes that aren&#8217;t database columns. It works with anything for which there&#8217;s an assignment method:</p>
<pre># Suppose that your 'users' table only has a 'name' column.
class User &lt; ActiveRecord::Base
  default_value_for :name, 'Joe'
  default_value_for :age, 20
  default_value_for :registering, true

  attr_accessor :age

  def registering=(value)
    @registering = true
  end
end

user = User.new
user.age    # =&gt; 20
user.instance_variable_get('@registering')    # =&gt; true</pre>
<h3>Caveats</h3>
<p>A conflict can occur if your model class overrides the &#8216;initialize&#8217; method, because this plugin overrides &#8216;initialize&#8217; as well to do its job.</p>
<pre>class User &lt; ActiveRecord::Base
  def initialize  # &lt;-- this constructor causes problems
    super(:name =&gt; 'Name cannot be changed in constructor')
  end
end</pre>
<p>We recommend you to alias chain your initialize method in models where you use <code>default_value_for</code>:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :age, 20

  def initialize_with_my_app
    initialize_without_my_app(:name =&gt; 'Name cannot be changed in constructor')
  end

  alias_method_chain :initialize, :my_app
end</pre>
<p>Also, stick with the following rules:</p>
<ul>
<li>There is no need to <code>alias_method_chain</code> your initialize method in models that don&#8217;t use <code>default_value_for</code>.</li>
<li>Make sure that <code>alias_method_chain</code> is called <b>after</b> the last <code>default_value_for</code> occurance.</li>
</ul>
<h2>When (not) to use default_value_for?</h2>
<p>You can also specify default values in the database schema. For example, you can specify a default value in a migration as follows:</p>
<pre>create_table :users do |t|
  t.string    :username,  :null =&gt; false, :default =&gt; 'default username'
  t.integer   :age,       :null =&gt; false, :default =&gt; 20
  t.timestamp :last_seen, :null =&gt; false, :default =&gt; Time.now
end</pre>
<p>This has the same effect as passing the default value as the second argument to <code>default_value_for</code>:</p>
<pre>user = User.new
user.username   # =&gt; 'default username'
user.age        # =&gt; 20
user.timestamp  # =&gt; Mon Sep 22 18:31:47 +0200 2008</pre>
<p>It&#8217;s recommended that you use this over <code>default_value_for</code> whenever possible.</p>
<p>However, it&#8217;s not possible to specify a schema default for serialized columns. With <code>default_value_for</code>, you can:</p>
<pre>class User &lt; ActiveRecord::Base
  serialize :color
  default_value_for :color, [255, 0, 0]
end</pre>
<p>And if schema defaults don&#8217;t provide the flexibility that you need, then <code>default_value_for</code> is the perfect choice. For example, with <code>default_value_for</code> you could specify a per-environment default:</p>
<pre>class User &lt; ActiveRecord::Base
  if RAILS_ENV == "development"
    default_value_for :is_admin, true
  end
end</pre>
<p>Or, as you&#8217;ve seen in an earlier example, you can use <code>default_value_for</code> to generate a default random UUID:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :uuid do
    UuidGenerator.new.generate_uuid
  end
end</pre>
<p>Or you could use it to generate a timestamp that&#8217;s relative to the time at which the record is instantiated:</p>
<pre>class User &lt; ActiveRecord::Base
  default_value_for :account_expires_at do
    3.years.from_now
  end
end

User.new.account_expires_at   # =&gt; Mon Sep 22 18:43:42 +0200 2008
sleep(2)
User.new.account_expires_at   # =&gt; Mon Sep 22 18:43:44 +0200 2008</pre>
<p>Finally, it&#8217;s also possible to specify a default via an association:</p>
<pre># Has columns: 'name' and 'default_price'
class SuperMarket &lt; ActiveRecord::Base
  has_many :products
end

# Has columns: 'name' and 'price'
class Product &lt; ActiveRecord::Base
  belongs_to :super_market

  default_value_for :price do |product|
    product.super_market.default_price
  end
end

super_market = SuperMarket.create(:name =&gt; 'Albert Zwijn', :default_price =&gt; 100)
soap = super_market.products.create(:name =&gt; 'Soap')
soap.price   # =&gt; 100</pre>
<h3>What about before_validate/before_save?</h3>
<p>True, <code>before_validate</code> and <code>before_save</code> does what we want if we&#8217;re only interested in filling in a default before saving. However, if one wants to be able to access the default value even before saving, then be prepared to write a lot of code. Suppose that we want to be able to access a new record&#8217;s UUID, even before it&#8217;s saved. We could end up with the following code:</p>
<pre># In the controller
def create
  @user = User.new(params[:user])
  @user.generate_uuid
  email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
  @user.save!
end

# Model
class User &lt; ActiveRecord::Base
  before_save :generate_uuid_if_necessary

  def generate_uuid
    self.uuid = ...
  end

  private
    def generate_uuid_if_necessary
      if uuid.blank?
        generate_uuid
      end
    end
end</pre>
<p>The need to manually call <code>generate_uuid</code> here is ugly, and one can easily forget to do that. Can we do better? Let&#8217;s see:</p>
<pre># Controller
def create
  @user = User.new(params[:user])
  email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
  @user.save!
end

# Model
class User &lt; ActiveRecord::Base
  before_save :generate_uuid_if_necessary

  def uuid
    value = read_attribute('uuid')
    if !value
      value = generate_uuid
      write_attribute('uuid', value)
    end
    value
  end

  # We need to override this too, otherwise User.new.attributes won't return
  # a default UUID value. I've never tested with User.create() so maybe we
  # need to override even more things.
  def attributes
    uuid
    super
  end

  private
    def generate_uuid_if_necessary
      uuid  # Reader method automatically generates UUID if it doesn't exist
    end
end</pre>
<p>That&#8217;s an awful lot of code. Using <code>default_value_for</code> is easier, don&#8217;t you think?</p>
<h3>What about other plugins?</h3>
<p>I&#8217;ve only been able to find 2 similar plugins:</p>
<ul>
<li>Default Value: <a href="http://agilewebdevelopment.com/plugins/default_value">http://agilewebdevelopment.com/plugins/default_value</a></li>
<li>ActiveRecord Defaults: <a href="http://agilewebdevelopment.com/plugins/activerecord_defaults">http://agilewebdevelopment.com/plugins/activerecord_defaults</a></li>
</ul>
<p><em>Default Value</em> appears to be unmaintained; its SVN link is broken. This leaves only <em>ActiveRecord Defaults</em>. However, it is semantically dubious, which leaves it wide open for corner cases. For example, it is not clearly specified what ActiveRecord Defaults will do when attributes are protected by <code>attr_protected</code> or <code>attr_accessible</code>. It is also not clearly specified what one is supposed to do if one needs a custom <code>initialize</code> method in the model.</p>
<p>I&#8217;ve taken my time to thoroughly document default_value_for&#8217;s behavior.</p>
<h2>Credits</h2>
<p>I&#8217;ve wanted such functionality for a while now and it baffled me that ActiveRecord doesn&#8217;t provide a clean way for me to specify default values. After reading <a href="http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935">http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935</a>, it became clear that someone needs to write a plugin. This is the result.</p>
<p>Thanks to Pratik Naik for providing the initial code snippet on which this plugin is based on: <a href="http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model">http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model</a></p>
<p>If you like this plugin, then please <a href="http://www.modrails.com/enterprise.html">consider donating</a> and/or recommending us:</p>
<table class="wwr">
<tr>
<td>
<a href="http://www.workingwithrails.com/person/11402-hongli-lai"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Hongli Lai</a>
</td>
<td>
<a href="http://www.workingwithrails.com/person/12429-ninh-bui"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Ninh Bui</a>
</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2008/10/03/47/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Internationalization features in Rails edge</title>
		<link>http://blog.phusion.nl/2008/08/27/internationalization-features-in-rails-edge/</link>
		<comments>http://blog.phusion.nl/2008/08/27/internationalization-features-in-rails-edge/#comments</comments>
		<pubDate>Wed, 27 Aug 2008 21:17:48 +0000</pubDate>
		<dc:creator>Hongli Lai</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=44</guid>
		<description><![CDATA[The development version of Ruby on Rails has cool new internationalization features. Although the framework itself doesn&#8217;t provide a lot of I18N functionality, it does provide the necessary hooks for plugins to implement I18N however they see fit. Simon Tokumine has written an I18N demo application to show you what Rails is capable of, when [...]]]></description>
			<content:encoded><![CDATA[<p>The development version of Ruby on Rails has cool new internationalization features. Although the framework itself doesn&#8217;t provide a lot of I18N functionality, it does provide the necessary hooks for plugins to implement I18N however they see fit. <a href="http://github.com/tokumine/i18n_demo_app/tree/master">Simon Tokumine has written an I18N demo application</a> to show you what Rails is capable of, when used in combination with the <a href="http://agilewebdevelopment.com/plugins/localized_dates">localized_dates</a> plugin.</p>
<p>We&#8217;ve deployed the demo application at <a href="http://i18n-demo.phusion.nl/">http://i18n-demo.phusion.nl/</a>. Check it out.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2008/08/27/internationalization-features-in-rails-edge/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ruby Enterprise Edition website &#8220;launched&#8221;</title>
		<link>http://blog.phusion.nl/2008/05/14/ruby-enterprise-edition-website-launched/</link>
		<comments>http://blog.phusion.nl/2008/05/14/ruby-enterprise-edition-website-launched/#comments</comments>
		<pubDate>Wed, 14 May 2008 18:16:31 +0000</pubDate>
		<dc:creator>Hongli Lai</dc:creator>
				<category><![CDATA[Phusion Passenger]]></category>
		<category><![CDATA[Ruby Enterprise Edition]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=16</guid>
		<description><![CDATA[Well hello there. Since you guys must probably be bored out of your ***** waiting for Ruby Enterprise Edition to be released, let&#8217;s play a little play to let the time pass by quicker mmm&#8217;kay? A riddle actually, see http://www.RubyEnterpriseEdition.com for more information Be sure to scroll down, the next hint will be revealed on [...]]]></description>
			<content:encoded><![CDATA[<p>Well hello there.</p>
<p>Since you guys must probably be bored out of your ***** waiting for Ruby Enterprise Edition to be released, let&#8217;s play a little play to let the time pass by quicker mmm&#8217;kay? <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>A riddle actually, see <a href="http://www.RubyEnterpriseEdition.com">http://www.RubyEnterpriseEdition.com</a> for more information <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Be sure to scroll down, the next hint will be revealed on May 20th, 2008.</p>
<p>We&#8217;re looking forward to reading your submissions <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>Cheers,<br />
Hongli Lai<br />
Ninh Bui</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2008/05/14/ruby-enterprise-edition-website-launched/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Passenger (mod_rails) 1.0.5 released</title>
		<link>http://blog.phusion.nl/2008/05/07/passenger-mod_rails-105-released/</link>
		<comments>http://blog.phusion.nl/2008/05/07/passenger-mod_rails-105-released/#comments</comments>
		<pubDate>Wed, 07 May 2008 19:21:20 +0000</pubDate>
		<dc:creator>Hongli Lai</dc:creator>
				<category><![CDATA[Phusion Passenger]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=7</guid>
		<description><![CDATA[Passenger version 1.0.5 has just been released. Because of time constraints we haven&#8217;t had time to write announcements for 1.0.3 and 1.0.4, so here&#8217;s a summary of changes in 1.0.3, 1.0.4 and 1.0.5: Fixed MacOS X support, this time for real 1.0.2 fixed compatibility for MacOS X. Unfortunately, the fix broke 64-bit Linux. 1.0.4 fixed [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.modrails.com/">Passenger</a> version 1.0.5 has just been released. Because of time constraints we haven&#8217;t had time to write announcements for 1.0.3 and 1.0.4, so here&#8217;s a summary of changes in 1.0.3, 1.0.4 and 1.0.5:</p>
<dl>
<dt>Fixed MacOS X support, this time for real</dt>
<dd>
<p>1.0.2 fixed compatibility for MacOS X. Unfortunately, the fix broke 64-bit Linux. 1.0.4 fixed support for 64-bit Linux, but that fix broke MacOS X again.</p>
<p>1.0.5 fixes support for MacOS X *and* 64-bit Linux. It hadn&#8217;t been easy to get this right, and we kindly thank all the testers who have helped us with this. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><b>Note to C/C++ developers:</b> if you&#8217;re looking for cross-platform file descriptor passing code, please feel free to copy &#038; paste it from Passenger&#8217;s source code. Every single code example about file descriptor passing that we could find on the Internet, has portability problems (= works on 64-bit Linux but not 64-bit OS X, or vice versa). We believe that we&#8217;ve solved all those portability issues.</p>
</dd>
<dt>Fixed support for Ruby on Rails 1.2</dt>
<dd>Version 1.0.2 broke support for Ruby on Rails 1.2, because it used a feature that only 2.0 and up has. Version 1.0.3 fixed this problem.</dd>
</dl>
<h2>How do I upgrade?</h2>
<p>Just install it like you did the first time:</p>
<pre>gem install passenger</pre>
<p>and</p>
<pre>passenger-install-apache2-module</pre>
<p>Please don’t forget to <b>copy &#038; paste the Apache config snippet</b> that the installer gives you.</p>
<p>At the time of writing, RubyForge is still busy updating all their gem mirror servers. So if <em>gem install passenger</em> didn&#8217;t work for you, then please download it from HTTP at: <a href="http://rubyforge.org/frs/?group_id=5873">http://rubyforge.org/frs/?group_id=5873</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2008/05/07/passenger-mod_rails-105-released/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Phusion Passenger (mod_rails) version 1.0.2 released, and more</title>
		<link>http://blog.phusion.nl/2008/04/29/phusion-passenger-mod_rails-version-102-released-and-more/</link>
		<comments>http://blog.phusion.nl/2008/04/29/phusion-passenger-mod_rails-version-102-released-and-more/#comments</comments>
		<pubDate>Tue, 29 Apr 2008 13:31:16 +0000</pubDate>
		<dc:creator>Ninh Bui</dc:creator>
				<category><![CDATA[Phusion Passenger]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.phusion.nl/?p=3</guid>
		<description><![CDATA[It has been two weeks since the release of Passenger version 1.0.1. More and more people are switching to Passenger, and most are very pleased with the quality of our initial release. But in these past 2 weeks, we&#8217;ve continued to make improvements to Passenger. So today, we&#8217;re happy to announce the release of Passenger [...]]]></description>
			<content:encoded><![CDATA[<p>It has been two weeks since the release of Passenger version 1.0.1. <a href="http://www.alloycode.com/2008/4/26/another-passenger-on-the-mod_rails">More and more</a> people are <a href="http://www.koziarski.net/archives/2008/4/26/now-running-on-passenger">switching</a> to Passenger, and most are very pleased with the quality of our initial release. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  But in these past 2 weeks, we&#8217;ve continued to make improvements to Passenger. So today, we&#8217;re happy to announce the release of <a href="http://www.modrails.com/">Passenger</a> version 1.0.2. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<table class="wwr">
<tr>
<td>
<a href="http://www.workingwithrails.com/person/11402-hongli-lai"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Hongli Lai</a>
</td>
<td>
<a href="http://www.workingwithrails.com/person/12429-ninh-bui"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Ninh Bui</a>
</td>
</tr>
</table>
<h2>Featured improvements and changes</h2>
<dl>
<dt>100% support for MacOS X&#8217;s default Apache</dt>
<dd>
<p>
Passenger has always supported MacOS X. This fact is demonstrated in our screencast, created by Ryan Bates on a Mac. However, there was an inconvenience: Passenger was incompatible with the default Apache installation, as provided by OS X. The installer warned about that. As a result, OS X users had to install Apache via MacPorts or by hand.</p>
<p>But no more. Thanks for the help of <a href="http://www.innerfuse.biz/blog/">Weyert de Boer</a> and <a href="http://www.fngtps.com/2008/04/using-passenger-on-osx-for-rails-development">the people at Fingertips</a>, we&#8217;ve been able to track down the problem. <strong>Passenger now fully supports MacOS X&#8217;s default Apache!</strong> There is no need to install Apache via MacPorts anymore. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
</dd>
<dt>RubyGems-related fixes: Rails &lt; 2.0 is now supported</dt>
<dd>
<p>The Passenger gem specifies Rails 2.0 as a dependency. This seemed to be a good idea at the time: Passenger is to be used in combination with Rails, and we figured that by specifying Rails as a dependency, the user will have one command less to type.</p>
<p>But it turned out that <a href="http://code.google.com/p/phusion-passenger/issues/detail?id=25">some RubyGems versions will load Rails 2.0 during Passenger&#8217;s startup</a>, even though Passenger didn&#8217;t explicitly tell RubyGems to do that. As a result, some people were having trouble with using Passenger with Rails &lt; version 2.0. This issue has been fixed.</p>
</dd>
<dt>Memory statistics tool</dt>
<dd>
<p>Some people have attempted to analyze Passenger&#8217;s memory usage. But standard tools such as &#8216;top&#8217; and &#8216;ps&#8217; <a href="http://groups.google.com/group/phusion-passenger/msg/1fd1c233456d3180">don&#8217;t always report the correct memory usage</a>.</p>
<p>We&#8217;ve provided a tool, <strong>passenger-memory-stats</strong>, which allows people to easily analyze Passenger&#8217;s and Apache&#8217;s <strong>real</strong> memory usage. For example:</p>
<pre>$ sudo ./bin/passenger-memory-stats
------------- Apache processes --------------
PID    PPID  Threads  VMSize   Private  Name
---------------------------------------------
5947   1     9        90.6 MB  0.5 MB   /usr/sbin/apache2 -k start
5948   5947  1        18.9 MB  0.7 MB   /usr/sbin/fcgi-pm -k start
6029   5947  1        42.7 MB  0.5 MB   /usr/sbin/apache2 -k start
6030   5947  1        42.7 MB  0.5 MB   /usr/sbin/apache2 -k start
6031   5947  1        42.5 MB  0.3 MB   /usr/sbin/apache2 -k start
6033   5947  1        42.5 MB  0.4 MB   /usr/sbin/apache2 -k start
6034   5947  1        50.5 MB  0.4 MB   /usr/sbin/apache2 -k start
23482  5947  1        82.6 MB  0.4 MB   /usr/sbin/apache2 -k start
### Processes: 8
### Total private dirty RSS: 3.50 MB

--------- Passenger processes ---------
PID    Threads  VMSize   Private  Name
---------------------------------------
6026   1        10.9 MB  4.7 MB   Passenger spawn server
23481  1        26.7 MB  3.0 MB   Passenger FrameworkSpawner: 2.0.2
23791  1        26.8 MB  2.9 MB   Passenger ApplicationSpawner: /var/www/projects/app1-foobar
23793  1        26.9 MB  17.1 MB  Rails: /var/www/projects/app1-foobar
### Processes: 4
### Total private dirty RSS: 27.76 MB</pre>
<p>The <strong>private dirty RSS</strong> field shows the *real* memory usage of processes. Here, we see that all the Apache worker processes only take less than 1 MB memory each. This is a lot less than the 50 MB-ish memory usage as shown in the &#8220;VMSize&#8221; column (which is what a lot of people think is the real memory usage, but is actually not).</p>
<p>Please note that this tool only works on Linux. Unfortunately other operating systems don&#8217;t provide facilities for determining processes&#8217; private dirty RSS.</p>
</dd>
<dt>Improved stability</dt>
<dd>
<p>If the framework spawner server or application spawner crashes, then Passenger 1.0.1 will keep showing error messages until one restarts Apache. Passenger 1.0.2 will automatically restart spawner servers when they crash, thus lowering maintenance burden even more.</p>
</dd>
<dt>Setting ENV['RAILS_ENV'] in environment.rb now works</dt>
<dd>
A bug caused ENV['RAILS_ENV'] in environment.rb to be ignored. This has now been fixed.
</dd>
<dt>Support for custom page caching directories</dt>
<dd>
<p>Page caching was supported by Passenger, but setting a custom (non-standard) page caching directory <a href="http://code.google.com/p/phusion-passenger/issues/detail?id=9">did not work</a>. This has now been fixed. But please note that Passenger won&#8217;t be able to accelerate page cache files in non-standard page caching directories.</p>
</dd>
<dt>Usability and documentation improvements</dt>
<dd>
<p>The community has provided a lot more insight on things that can go wrong. We&#8217;ve done our best to document all troubleshooting-related issue into our Users guide. We&#8217;ve also adapted some error messages so that users can solve the problem without reading the manual.</p>
<p>Thanks for all the feedback people! <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
</dd>
<dt>Fixed conflicts with system-provided Boost library</dt>
<dd>
<p>Passenger makes use of the Boost C++ library. Its sources are included into the Passenger sources. But if the system already has a different Boost version installed, then the two Boost libraries would conflict with each other, and Passenger would fail to install. We&#8217;ve made sure that this doesn&#8217;t happen: now, installation will succeed even if there&#8217;s already another Boost version installed.</p>
</dd>
<dt>Improved SSL compatibility</dt>
<dd>
<p>There was a problem with SSL hosts, which would only be triggered if &#8220;SSLOptions +ExportCertData&#8221; is set. This <a href="http://code.google.com/p/phusion-passenger/issues/detail?id=20">issue</a> has now been fixed.</p>
</dd>
<dt>Improved support for graceful restarts</dt>
<dd>
<p>If you installed Passenger for the first time, then the first graceful Apache restart would not properly initialize Passenger. This issue has now been solved.</p>
</dd>
</dl>
<p>There are also a few small improvements and changes that aren&#8217;t worth mentioning.</p>
<h2>How do I upgrade?</h2>
<p>Just install it like you did the first time:</p>
<pre>gem install passenger</pre>
<p>and</p>
<pre>passenger-install-apache2-module</pre>
<p>Please don&#8217;t forget to <strong>copy &amp; paste the Apache config snippet</strong> that the installer gives you.</p>
<h2>Enterprise Licenses, donations and t-shirts</h2>
<p>In many ways, Phusion Passenger (mod_rails) has been an overwhelming success to us, and we&#8217;re very grateful for the community support you guys have given us. Also, a lot of companies and individuals have been more than generous in purchasing an <a href="http://www.modrails.com/enterprise.html">Enterprise License</a> for Phusion Passenger (mod_rails). In particular, we&#8217;d like to thank all the people who have donated over a certain amount and thought it would only be fitting to send them something concrete as a reminder of this generous act. After giving it a lot of thought, we came with something really shabby (or at least we &#8216;part-time fashion connoisseurs&#8217; think so <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ).</p>
<p>To celebrate our first successful open source product launch here at Phusion, we&#8217;ve decided to <strong>silkscreen-print 100 limited edition Phusion t-shirts</strong>, each hand-numbered from 1 to 100. A few of these will go to our friends at <a href="http://www.apple.com">Apple</a>, <a href="http://www.sun.com">Sun Microsystems</a> and <a href="http://37signals.com">37 signals</a>, and the remainder of the shirts will go to those who have donated over 200 USD in total (we&#8217;ll take care of the shipping fees). Needless to say, these shirts are going to be hot as heck at IT conferences such as <a href="http://www.railsconf.org/">Railsconf</a>, as they have been silkscreen-printed by the same people who are responsible for printing the shirts for the uberhip brands <a href="http://www.rockwellclothing.com">Rockwell</a>, <a href="http://www.freshcotton.com">Freshcotton</a> and <a href="http://www.top-notch.nl">Top Notch</a>. The shirts themselves are super premium t&#8217;s which weigh 205gr/m<sup>2</sup>. To emphasize this even more, we&#8217;ve arranged for a photo shoot with a few professional lady models <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  and just like you, we can&#8217;t wait to see the result of this. Hopefully, you&#8217;ll be able to see the result soon!</p>
<p><a href='http://blog.phusion.nl/wp-content/uploads/2008/04/artist_impression.jpg' class="image"><img src="http://blog.phusion.nl/wp-content/uploads/2008/04/artist_impression.jpg" alt="" title="Artist impression of Phusion t-shirt" width="207" height="212" class="alignnone size-medium wp-image-4" /></a><span class="image_title">An artist&#8217;s impression of the Phusion t-shirt</span></p>
<p>People who haven&#8217;t donated yet, or donated less than 200 USD but who want a piece of the t-shirt action as well will get the opportunity to &#8220;set this right&#8221; in the second (current) and third batch of enterprise licenses by donating the remainder amount to us under the same PayPal account. We&#8217;ll try to sort this out then as soon as possible. Needless to say, first come, first serve will be maintained, <strong>so if you want a shirt, be sure to act fast as supplies are bound to not last for very long!</strong> You probably don&#8217;t want to be figuring out that you actually wanted a shirt like this when it&#8217;s too late right? <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Also, we&#8217;ve only got a limited amount in each size (especially the sizes small and XXL are likely to run out fast, and not to mention the girlie sized shirts for the ladies).</p>
<p>Lastly, we&#8217;re <em>very</em> grateful for all donations, and it is for this reason that we&#8217;ll also occasionaly randomly pick a few people from the donation list that haven&#8217;t donated over 200 USD for a Phusion t-shirt as well <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . So in short, whatever amount you decide to donate, be sure to include your shirt size as well from now on as it might be your lucky day <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h2>RailsConf</h2>
<p>Not only community wise, but also commercial wise, Phusion Passenger has opened up a lot of doors for Phusion that would otherwise likely have remained closed. For starters, we&#8217;ll be talking at Railsconf in a little more than a month about Phusion Passenger and the highly anticipated <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a>. It seems that the latter has already generated a lot of buzz and that this for the greater part, is because of its name. We actually think this is a good thing since we don&#8217;t believe that there is such a thing as bad publicity. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Don&#8217;t worry too much about it though, Railsconf will provide us with the perfect opportunity to dive into this subject a little bit deeper and hopefully, you&#8217;ll agree with us on that it&#8217;ll make a lot of sense to call it Ruby Enterprise Edition. We&#8217;ll also do something that is probably unprecedented with regards to talks so be sure to check us out over there, even if it&#8217;s just for the meet and greet / casual chat. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><a href='http://en.oreilly.com/rails2008/public/schedule/detail/4354' class="image"><img src="http://blog.phusion.nl/wp-content/uploads/2008/04/railsconf.jpg" alt="" title="We\&#039;re on the RailsConf speakers list!" class="alignnone size-thumbnail wp-image-5" /></a><span class="image_title">We&#8217;re on the RailsConf speakers list!</span></p>
<h2>Side notes</h2>
<p>We&#8217;re also still hard at work on writing a series of articles on both Phusion Passenger as well as Ruby Enterprise Edition from which we&#8217;ll also distill a scientific paper to be published on eeprints at the <a href="http://www.utwente.nl">University of Twente</a> (rocking! <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ). Needless to say, these articles will be published for your reading pleasure as well. <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>As you may have already noticed, Phusion recently consisted of mainly <a href="http://www.workingwithrails.com/person/11402-hongli-lai">Hongli Lai</a> and <a href="http://www.workingwithrails.com/person/12429-ninh-bui">Ninh Bui</a>. Even though we two make up for one hell of a team, we both definitely started feeling the growth pains of a healthy growing startup company. A little while ago we posted some job openings in the hopes of increasing Phusion&#8217;s capacity, but unfortunately, most of these applications were from outside of the Netherlands.</p>
<p>Today however, we&#8217;re pleased to announce that our good friend <a href="http://www.tinco.nl/">Tinco Andringa</a> has decided to join the fray by joining Phusion. He&#8217;s not alone in this though, since our other good friend Maurits Dijkstra has also decided to do the same. And yes, the latter of the two IS related to the famous <a href="http://en.wikipedia.org/wiki/Edsger_Dijkstra">Edsger Dijkstra</a>, which you may already know from Dijkstra&#8217;s <a href="http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">shortest path algorithm</a> <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  (but that wasn&#8217;t the main reason why we wanted him on board at Phusion per se <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ) Just like with Hongli and I, Maurits&#8217; and Tinco&#8217;s computer science education find their origin at the Universiteit Twente and both have built a nice career on the side as software engineers as well: with this configuration, we hope to be able to even deliver better on our services and products!</p>
<p>Well, that wraps it up for today! Stay tuned though, as we&#8217;ve only started to &#8216;bring it on&#8217;! <img src='http://blog.phusion.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>With kind regards, your friends at Phusion,</p>
<table class="wwr">
<tr>
<td>
<a href="http://www.workingwithrails.com/person/11402-hongli-lai"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Hongli Lai</a>
</td>
<td>
<a href="http://www.workingwithrails.com/person/12429-ninh-bui"><img src="http://workingwithrails.com/images/tools/compact-small.jpg"/> Ninh Bui</a>
</td>
</tr>
</table>
<p>- Tinco Andringa<br />
- Maurits Dijkstra</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phusion.nl/2008/04/29/phusion-passenger-mod_rails-version-102-released-and-more/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
