<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Guillaume Maury's Ramblings</title><link>http://gom-jabbar.org</link><pubDate>Wed, 04 Feb 2009 04:37:51 GMT</pubDate><description /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="giom" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://gom-jabbar.org/articles.rss" /><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Fgom-jabbar.org%2Farticles.rss" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Fgom-jabbar.org%2Farticles.rss" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Fgom-jabbar.org%2Farticles.rss" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bloglines.com/sub/http://gom-jabbar.org/articles.rss" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fgom-jabbar.org%2Farticles.rss" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Fgom-jabbar.org%2Farticles.rss" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Fgom-jabbar.org%2Farticles.rss" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><item><title>Don't use css or table layout, use Sass and Compass</title><link>http://gom-jabbar.org/articles/2009/02/04/don-t-use-css-or-table-layout-use-sass-ad-compass</link><description>&lt;p&gt;Sorry for the tongue in cheek title, I&amp;#8217;m trying to bait the news.ycombinator crowd who got into another spiraling argument. Last time it was did php win? now it&amp;#8217;s CSS vs tables (this one is a recurring one).&lt;/p&gt;

&lt;p&gt;But, I have the solution to end this religious war, use compass and sass!&lt;/p&gt;

&lt;p&gt;Ok, just a summary for those too busy to read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I&amp;#8217;m not a designer and having to get the layout right is the activity I hate the most when making a web application&lt;/li&gt;

&lt;li&gt;I feel that a lot of shortcomings of CSS can be solved by using a framework like BluePrint&lt;/li&gt;

&lt;li&gt;But using blueprint negates the benefits of using semantic markup (since you start having weird classes like span-6 prepend-2)&lt;/li&gt;

&lt;li&gt;&lt;a href='http://haml.hamptoncatlin.com/docs/'&gt;Sass&lt;/a&gt; has a nifty feature called mixin and &lt;a href='http://wiki.github.com/chriseppstein/compass'&gt;Compass&lt;/a&gt; use it to provide the power of frameworks like BluePrint while still keeping semantic classes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So now let&amp;#8217;s get on with a tour of Sass and Compass&lt;/p&gt;

&lt;h3 id='what_is_sass'&gt;What is sass?&lt;/h3&gt;

&lt;p&gt;Remember when you first heard of haml combining the dreaded semantic indentation of Python and the use of gratuitous punctation from Perl (thanks to Giles Bowkett for &lt;a href='http://gilesbowkett.blogspot.com/2009/01/haml-brings-seaside-awesome-to-ruby.html'&gt;the description&lt;/a&gt;) to create a very cool and useful markup language. Well sass is the brain child from the same guy.&lt;/p&gt;

&lt;p&gt;What follows is yet another quick introduction of Sass (I should have instead just linked to the doc but it&amp;#8217;s too late&amp;#8230;)&lt;/p&gt;

&lt;p&gt;Example of sass code:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
#foo
  :font-width&lt;span class='Numbers'&gt; 1&lt;/span&gt;&lt;span class='Constants'&gt;em&lt;/span&gt;
  :border&lt;span class='Numbers'&gt; 1&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt; solid
  :padding
    left&lt;span class='Numbers'&gt;  10&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt;
    right&lt;span class='Numbers'&gt; 5&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;a&lt;/span&gt;
    :text-decoration none
&lt;/pre&gt;
&lt;p&gt;which compiles down to the following CSS&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='CssSelectorsId'&gt;&lt;span class='CssSelectorsId'&gt;#&lt;/span&gt;foo&lt;/span&gt; { &lt;span class='CssPropertyKeyword'&gt;font&lt;/span&gt;-&lt;span class='CssPropertyKeyword'&gt;width&lt;/span&gt;: &lt;span class='Numbers'&gt;1&lt;/span&gt;&lt;span class='CssUnits'&gt;em&lt;/span&gt;; &lt;span class='CssPropertyKeyword'&gt;border&lt;/span&gt;: &lt;span class='Numbers'&gt;1&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt; &lt;span class='CssPropertyValue'&gt;solid&lt;/span&gt;; &lt;span class='CssPropertyKeyword'&gt;padding-left&lt;/span&gt;: &lt;span class='Numbers'&gt;10&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;; &lt;span class='CssPropertyKeyword'&gt;padding-right&lt;/span&gt;: &lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;; }
&lt;span class='CssSelectorsId'&gt;&lt;span class='CssSelectorsId'&gt;#&lt;/span&gt;foo&lt;/span&gt; &lt;span class='CssSelectorsElements'&gt;a&lt;/span&gt; {&lt;span class='CssPropertyKeyword'&gt;text-decoration&lt;/span&gt;: &lt;span class='CssPropertyValue'&gt;none&lt;/span&gt;;}
&lt;/pre&gt;
&lt;p&gt;So like with Haml, Sass gets rid of redundant markup (like the braces and ;) and instead uses semantic indentation to distinguish rules.&lt;/p&gt;

&lt;h4 id='variables_in_sass'&gt;Variables in Sass&lt;/h4&gt;

&lt;p&gt;But there is more, Sass also support variables:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='Variables'&gt;!success_color&lt;/span&gt; = &lt;span class='Constants'&gt;#7fb236&lt;/span&gt;
.success
  :color= &lt;span class='Variables'&gt;!success_color&lt;/span&gt;
.success_box
  :background-color=  &lt;span class='Variables'&gt;!success_color&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s an easy way to change colors in your layouts by just changing the value of the variable. Magic numbers have long been a code smell when programming, why shouldn&amp;#8217;t it be the same with CSS?&lt;/p&gt;

&lt;h4 id='mixins_and_sass'&gt;Mixins and Sass&lt;/h4&gt;

&lt;p&gt;Sass has a nice thing called mixins. Instead of copying and pasting some CSS code you always find yourself using, you can just use a mixin that will define this code to be reused later.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='Variables'&gt;!border_highlight_color&lt;/span&gt;= &lt;span class='Constants'&gt;#efefef&lt;/span&gt;
=message_box
  :border=&lt;span class='Numbers'&gt; 2&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt; solid &lt;span class='Variables'&gt;!border_highlight_color&lt;/span&gt;
  :padding&lt;span class='Numbers'&gt; 20&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt;
  
.success
  +message_box
  :color= &lt;span class='Variables'&gt;!success_color&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;will compile to&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='CssSelectorsClassname'&gt;&lt;span class='CssSelectorsClassname'&gt;.&lt;/span&gt;success&lt;/span&gt; {
  &lt;span class='CssPropertyKeyword'&gt;border&lt;/span&gt;: &lt;span class='Numbers'&gt;2&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt; &lt;span class='CssPropertyValue'&gt;solid&lt;/span&gt; &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;#&lt;/span&gt;efefef&lt;/span&gt;
  padding:&lt;span class='Numbers'&gt; 20&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;
  color: &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;#&lt;/span&gt;7fb236&lt;/span&gt;
}
&lt;/pre&gt;
&lt;p&gt;So now at last, you can keep your style sheets DRY, no need to hang them outside in the sun&amp;#8230; (sorry for the lame attempt of humor, no need to throw tomatoes, it won&amp;#8217;t happen again)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;em&gt;As said in the comment below by beejamin, the example is rather contrived and in this case it would make more sense to just add a message_box class to the element.&lt;/em&gt; A more complex and less contrived mixin example, with parameters is the mixin to layout list horizontally from Compass&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
=horizontal-list(&lt;span class='Variables'&gt;!padding&lt;/span&gt; =&lt;span class='Numbers'&gt; 4&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt;)
  +reset-box-model
  +clearfix
  &lt;span class='ControlStructures'&gt;li&lt;/span&gt;
    +no-bullet
    :white-space nowrap
    :float left
    :padding
      :left= &lt;span class='Variables'&gt;!padding&lt;/span&gt;
      :right= &lt;span class='Variables'&gt;!padding&lt;/span&gt;
    &amp;amp;.first
      :padding-left&lt;span class='Numbers'&gt; 0&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt;
    &amp;amp;.last
      :padding-right&lt;span class='Numbers'&gt; 0&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt;
&lt;/pre&gt;
&lt;h4 id='sass_and_script_functions'&gt;Sass and Script functions&lt;/h4&gt;

&lt;p&gt;Sass has a few built-in functions allowing you to do things like this:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  .menu_bar
    :background-color= hsl(&lt;span class='Numbers'&gt;66&lt;/span&gt;,&lt;span class='Numbers'&gt; 6&lt;/span&gt;,&lt;span class='Numbers'&gt; 82&lt;/span&gt;)
    :width= abs(&lt;span class='Numbers'&gt;20&lt;/span&gt;&lt;span class='Constants'&gt;px&lt;/span&gt; * &lt;span class='Numbers'&gt;-4&lt;/span&gt;)
&lt;/pre&gt;
&lt;p&gt;will compile to&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='CssSelectorsClassname'&gt;&lt;span class='CssSelectorsClassname'&gt;.&lt;/span&gt;menu_bar_color&lt;/span&gt; {
  &lt;span class='CssPropertyKeyword'&gt;background-color&lt;/span&gt;: &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;#&lt;/span&gt;d3d4ce&lt;/span&gt;;
  &lt;span class='CssPropertyKeyword'&gt;width&lt;/span&gt;: &lt;span class='Numbers'&gt;80&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;; }
&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s easy to add new functions by monkey patching the Sass:Scripts::Functions module. For example see &lt;a href='http://gist.github.com/58005'&gt;this gist&lt;/a&gt; where I added functions to determine the height and width of an image.&lt;/p&gt;

&lt;h3 id='wrapping_it_up_a_cool_example_of_sass'&gt;Wrapping it up, a cool example of Sass&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;em&gt;I decided to add this section to better show the power of using mixins and functions in Sass (this uses the height function as explained above that you can find in &lt;a href='http://gist.github.com/58005'&gt;this gist&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One technique that is often used to speed up load time is to use &lt;a href='http://www.alistapart.com/articles/sprites'&gt;CSS sprites&lt;/a&gt;. I usually use this mixin to do it:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
=vertical_background_sprite(&lt;span class='Variables'&gt;!img&lt;/span&gt;, &lt;span class='Variables'&gt;!n&lt;/span&gt;, &lt;span class='Variables'&gt;!total&lt;/span&gt;)
  &lt;span class='Variables'&gt;!sprite_height&lt;/span&gt;= height(&lt;span class='Variables'&gt;!img&lt;/span&gt;)/&lt;span class='Variables'&gt;!total&lt;/span&gt;
  :background= transparent &lt;span class='Variables'&gt;url(!img)&lt;/span&gt;&lt;span class='Numbers'&gt; 0&lt;/span&gt; (&lt;span class='Variables'&gt;!sprite_height&lt;/span&gt; * -(&lt;span class='Variables'&gt;!n&lt;/span&gt; &lt;span class='Numbers'&gt;- 1&lt;/span&gt;)) no-repeat
  :height= &lt;span class='Variables'&gt;!sprite_height&lt;/span&gt;
  
#new_pick
  +vertical_background_sprite(/images/item_info_icons.png,&lt;span class='Numbers'&gt; 1&lt;/span&gt;,&lt;span class='Numbers'&gt; 5&lt;/span&gt;)
#new_favorite
  +vertical_background_sprite(/images/item_info_icons.png,&lt;span class='Numbers'&gt; 2&lt;/span&gt;,&lt;span class='Numbers'&gt; 5&lt;/span&gt;)
#tell_friend
  +vertical_background_sprite(/images/item_info_icons.png,&lt;span class='Numbers'&gt; 3&lt;/span&gt;,&lt;span class='Numbers'&gt; 5&lt;/span&gt;)
#share_link
  +vertical_background_sprite(/images/item_info_icons.png,&lt;span class='Numbers'&gt; 4&lt;/span&gt;,&lt;span class='Numbers'&gt; 5&lt;/span&gt;)
#report
  +vertical_background_sprite(/images/item_info_icons.png,&lt;span class='Numbers'&gt; 5&lt;/span&gt;,&lt;span class='Numbers'&gt; 5&lt;/span&gt;)
&lt;/pre&gt;
&lt;p&gt;Like this, I don&amp;#8217;t need to hardcode the exact size of the sprites I have in my image.&lt;/p&gt;

&lt;p&gt;For a programmer like me, Sass is a godsend, it makes my CSS code dry, more readable and make it feel more like a real programming language. Of course, the big problem is finding a designer that understands Sass&amp;#8230;&lt;/p&gt;

&lt;h3 id='compass'&gt;Compass&lt;/h3&gt;

&lt;p&gt;Compass is a meta framework for Sass, it uses the power of Sass&amp;#8217;s mixins to allow you to use frameworks like &lt;a href='http://www.blueprintcss.org/'&gt;BluePrint&lt;/a&gt;, &lt;a href='http://developer.yahoo.com/yui/grids/'&gt;YUI&lt;/a&gt; without having the semantic classes nightmare of having all your classes named barbaric names like span-1, prepend-5.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m going to use the &lt;a href='http://www.blueprintcss.org/'&gt;BluePrint&lt;/a&gt; library from compass as an example because that&amp;#8217;s what I use in my project.&lt;/p&gt;

&lt;p&gt;In a nutshell BluePrint is a CSS framework that gives you grid that is by default 950px with 24 columns 30 px each separated by a 10px gutter space. (all of this is customizable through the &lt;code&gt;!blueprint_grid_columns&lt;/code&gt;, &lt;code&gt;!blueprint_grid_width&lt;/code&gt; and &lt;code&gt;!blueprint_grid_margin&lt;/code&gt; variables).&lt;br /&gt;Compass provides mixins to make it easy to use the BluePrint grid.&lt;/p&gt;

&lt;p&gt;So if you have a div with an id of &lt;code&gt;sidebar&lt;/code&gt;, you can do this&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
#sidebar
  +column(&lt;span class='Numbers'&gt;5&lt;/span&gt;)
  +prepend(&lt;span class='Numbers'&gt;1&lt;/span&gt;)
&lt;/pre&gt;
&lt;p&gt;This will make the &lt;code&gt;#sidebar&lt;/code&gt; div be 5 columns wide, with one empty column behind it on the left. It will compile to the following CSS code:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='CssSelectorsId'&gt;&lt;span class='CssSelectorsId'&gt;#&lt;/span&gt;sidebar&lt;/span&gt; {
  &lt;span class='CssPropertyKeyword'&gt;float&lt;/span&gt;: &lt;span class='CssPropertyValue'&gt;left&lt;/span&gt;;
  &lt;span class='CssPropertyKeyword'&gt;width&lt;/span&gt;: &lt;span class='Numbers'&gt;190&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;;
  &lt;span class='CssPropertyKeyword'&gt;margin-right&lt;/span&gt;: &lt;span class='Numbers'&gt;10&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;;
  &lt;span class='CssPropertyKeyword'&gt;padding-left&lt;/span&gt;: &lt;span class='Numbers'&gt;40&lt;/span&gt;&lt;span class='CssUnits'&gt;px&lt;/span&gt;; }
&lt;/pre&gt;
&lt;p&gt;For those who need a fluid layout, there is &lt;code&gt;blueprint/modules/liquid.sass&lt;/code&gt; that provides a liquid layout.&lt;/p&gt;

&lt;p&gt;I find it very easy to use the Compass BluePrint mixins for layout and it brings me the flexibility of CSS (easy to adapt the design to say an iphone without changing the html markup, quicker to load in browsers,&amp;#8230;) while still having a very simple and quick way to style my page exactly as I want it to be.&lt;/p&gt;

&lt;p&gt;For more information on Compass and some good primers, visit the &lt;a href='http://acts-as-architect.blogspot.com/'&gt;blog of its creator&lt;/a&gt; and the &lt;a href='http://wiki.github.com/chriseppstein/compass'&gt;Compass wiki on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3 id='concrete_example_of_using_compass_and_sass_for_creating_a_layout_that_people_generally_use_tables_for'&gt;Concrete Example of using Compass and Sass for creating a layout that people generally use tables for&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: &lt;em&gt;After rereading this article, I thought that maybe I should show an example of Compass in action&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Say you want to create a four column layout&lt;/p&gt;

&lt;p&gt;For this in Sass (using Compass) you can do this:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  @import blueprint.sass

  &lt;span class='ControlStructures'&gt;body&lt;/span&gt;
    +blueprint-typography
    .container
      +container
  #header
    +column(&lt;span class='Numbers'&gt;24&lt;/span&gt;)
  #left_bar
    +column(&lt;span class='Numbers'&gt;7&lt;/span&gt;)
  #content
    +column(&lt;span class='Numbers'&gt;11&lt;/span&gt;)
  #fourth_column
    +column(&lt;span class='Numbers'&gt;1&lt;/span&gt;)
  #right_bar
    +column(&lt;span class='Numbers'&gt;5&lt;/span&gt;,last)
&lt;/pre&gt;
&lt;p&gt;So you just define how many columns of the blueprint grid you need for each of your columns&amp;#8230;&lt;/p&gt;

&lt;p&gt;and use the following haml:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
!!! Strict 
%html
  %head 
    %link{&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;stylesheet&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;type&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;text/css&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;media&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;screen&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;/css/four_columns.css&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;}
  %body
    .container
      #header
        %h1 Some nifty header
      #left_bar
        Left bar
      #content
        Lorem ipsum ad infinitum
      #fourth_column
        This is a 4th col  
      #right_bar
        Right bar
&lt;/pre&gt;
&lt;p&gt;And you can see the result in &lt;a href='http://files.gom-jabbar.org/four_columns.html'&gt;all its glory here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If instead you want to use liquid layout, you just need to add &lt;code&gt;@import blueprint/modules/liquid.sass&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;NB: Now I must confess that I never had to use a liquid layout in the projects I&amp;#8217;ve been working on with Sass and Compass and just now when I tried it didn&amp;#8217;t work (the last column fell off). After modifying the &lt;code&gt;!blueprint_liquid_grid_margin&lt;/code&gt; to 0.4em it worked. I&amp;#8217;ll ask on the mailing list about that and see how it goes&amp;#8230;&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t know about you, but I find that this is at least as simple as using a table layout and the html code is cleaner too. Of course this could have been done with blueprint but in this case we have kept semantic names for the ids and classes. We do lose one thing from this technique though: it&amp;#8217;s not easy to reorder the content without touching the markup (at least if we want to use the blueprint mixins)&lt;/p&gt;

&lt;p&gt;For those thinking that using such a grid is not flexible, remember we&amp;#8217;re using sass the size of the grid and number of column is defined by variables. So you can redefine the number of grid columns by setting &lt;code&gt;!blueprint_grid_columns&lt;/code&gt; (or &lt;code&gt;blueprint_liquid_grid_columns&lt;/code&gt; if you&amp;#8217;re using the liquid layout), the width of each grid column with &lt;code&gt;!blueprint_grid_width&lt;/code&gt; (or &lt;code&gt;!blueprint_liquid_grid_width&lt;/code&gt;), and so on&amp;#8230;&lt;/p&gt;

&lt;h3 id='dont_use_css_or_table_layouts_use_compass_and_sass'&gt;Don&amp;#8217;t use CSS or table layouts, use Compass and Sass&lt;/h3&gt;

&lt;p&gt;So to conclude with why you should use Compass and Sass&lt;/p&gt;

&lt;p&gt;Compass and Sass&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;allows you to make your layout code Dry&lt;/li&gt;

&lt;li&gt;behaves like a programming language, so you can have fun refactoring your code&lt;/li&gt;

&lt;li&gt;is easy to install and start with&lt;/li&gt;

&lt;li&gt;takes care of the IE 6 incompatibilities by using the code from frameworks (I also use the excellent &lt;a href='http://code.google.com/p/ie7-js/'&gt;ie7-js library from Dean Edwards&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;allows to easily design a grid based layout while still keeping semantic names&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I don&amp;#8217;t like spending a lot of time with a layout when I could spend some times on more productive things like the backend code or the javascript code of my website but Compass and Sass have considerably reduced the pain of having to make a website &amp;#8220;pretty&amp;#8221;. And compared to dealing with tables, I find the results much cleaner and maintainable.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=0a2WfMx3"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=0a2WfMx3" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=vdgYsfrS"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=vav0inli"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=vav0inli" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/q5WKu5w2LyM" height="1" width="1"/&gt;</description><pubDate>Wed, 04 Feb 2009 04:37:51 GMT</pubDate><guid>http://gom-jabbar.org/articles/2009/02/04/don-t-use-css-or-table-layout-use-sass-ad-compass</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>httperf and File Descriptors</title><link>http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors</link><description>&lt;p&gt;When running httperf if you get this error:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
httperf --timeout=5 --client=0/1 --server=domU-12-31-39-00-A9-F7 --port=80 --uri=/articles.html --rate=500 --send-buffer=4096 --recv-buffer=16384 --num-conns=20000 --num-calls=10
httperf: warning: open file limit &lt;span class='Operators'&gt;&amp;gt;&lt;/span&gt; FD_SETSIZE&lt;span class='Operators'&gt;;&lt;/span&gt; limiting max. &lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; of open files to FD_SETSIZE&lt;/span&gt;
Maximum connect burst length: 50

Total: connections 9789 requests 96039 replies 95959 test-duration 44.312 s

Connection rate: 220.9 conn/s (4.5 ms/conn, &lt;span class='Operators'&gt;&amp;lt;&lt;/span&gt;=1022 concurrent connections)
Connection &lt;span class='Functions'&gt;time&lt;/span&gt; [ms]: min 6.5 avg 4139.6 max 13432.2 median 3770.5 stddev 1697.6
Connection &lt;span class='Functions'&gt;time&lt;/span&gt; [ms]: connect 495.6
Connection length [replies/conn]: 9.998

Request rate: 2167.4 req/s (0.5 ms/req)
Request size [B]: 88.0

Reply rate [replies/s]: min 2054.9 avg 2250.7 max 2559.2 stddev 155.9 (8 samples)
Reply &lt;span class='Functions'&gt;time&lt;/span&gt; [ms]: response 242.4 transfer 123.3
Reply size [B]: header 242.0 content 17073.0 footer 0.0 (total 17315.0)
Reply status: 1xx=0 2xx=95959 3xx=0 4xx=0 5xx=0

CPU &lt;span class='Functions'&gt;time&lt;/span&gt; [s]: user 1.42 system 17.77 (user 3.2% system 40.1% total 43.3%)
Net I/O: 36803.9 KB/s (301.5*10^6 bps)

Errors: total 10405 client-timo 194 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 10211 addrunavail 0 ftab-full 0 other 0
&lt;/pre&gt;
&lt;p&gt;fd-unavail means that there was the per-process on the limit of open files has been exceded. httperf uses select() and uses a new file descriptor for each connection it opens concurrently. So let&amp;#8217;s increase the limit on file descriptors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit /etc/security/limits.conf and add the line &lt;code&gt;*       hard    nofile  65535&lt;/code&gt; (or instead of * you can put the username of the user for whom you want to change the limit)&lt;/li&gt;

&lt;li&gt;Edit /usr/include/bits/typesizes.h and change &lt;code&gt;#define __FD_SET_SIZE 1024&lt;/code&gt; to &lt;code&gt;#define __FD_SET_SIZE 65535&lt;/code&gt; (in /usr/include/sys/select.h &lt;code&gt;FD_SETSIZE&lt;/code&gt; is defined as &lt;code&gt;__FD_SETSIZE&lt;/code&gt;)&lt;/li&gt;

&lt;li&gt;Download and recompile httperf&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class='pastels_on_dark'&gt;
  wget ftp://ftp.hpl.hp.com/pub/httperf/httperf-0.9.0.tar.gz
  tar xvzf httperf-0.9.0.tar.gz
  cd httperf-0.9.0
  ./configure &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt; make
  sudo make install
&lt;/pre&gt;
&lt;p&gt;I&amp;#8217;ve tested those steps on ubuntu&lt;/p&gt;

&lt;p&gt;NB: This is one of the reason you should make sure that nginx is using epoll (linux) or kqueue (bsd) instead of select (this is determined at ./configure time but you can force it by using a use epoll in an events block).&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=hWBNVGa2"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=hWBNVGa2" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=if7mJWmm"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=up44noXo"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=up44noXo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/FC2NKZzujrE" height="1" width="1"/&gt;</description><pubDate>Wed, 04 Feb 2009 04:18:59 GMT</pubDate><guid>http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Merb-cache's methods</title><link>http://gom-jabbar.org/articles/2008/12/19/merb-cache-s-methods</link><description>&lt;h3 id='introduction'&gt;Introduction&lt;/h3&gt;

&lt;h5 id='important_note'&gt;Important note&lt;/h5&gt;

&lt;p&gt;A lot of this code needs the version of merb-cache found at &lt;a href='http://github.com/benschwarz/merb-cache'&gt;http://github.com/benschwarz/merb-cache&lt;/a&gt;. There have been a few patches made to it particularly for &lt;code&gt;eager_cache&lt;/code&gt; and &lt;code&gt;fetch_partial&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Beware that the code and api might change, I will keep this article up-to-date with the changes..&lt;/p&gt;

&lt;h3 id='the_cache_controller_method'&gt;The cache controller method&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;cache *actions, conditions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Caches the result of the action. Accepts two specific options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:store&lt;/code&gt; (or :stores) use the specified store&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:params&lt;/code&gt; list of params to pass to the store &lt;code&gt;conditions&lt;/code&gt; is then passed to the store so any conditions supported by the store (eg. &lt;code&gt;:expire_in&lt;/code&gt; for MemcachedStore) can be used.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; cache(&lt;span class='Variables'&gt;&lt;span class='Operators'&gt;*&lt;/span&gt;actions&lt;/span&gt;)
    conditions &lt;span class='Operators'&gt;=&lt;/span&gt; extract_options_from_args!(actions) &lt;span class='Operators'&gt;||&lt;/span&gt; {}
    actions.each {|&lt;span class='Variables'&gt;a&lt;/span&gt;| cache_action(a, conditions)}
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; cache_action(&lt;span class='Variables'&gt;action&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
    before(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;_cache_&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;action&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;_before&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, conditions.only(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;if&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;unless&lt;/span&gt;).merge(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;with&lt;/span&gt; =&amp;gt; [conditions], &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;only&lt;/span&gt; =&amp;gt; action))
    after(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;_cache_&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;action&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;_after&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, conditions.only(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;if&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;unless&lt;/span&gt;).merge(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;with&lt;/span&gt; =&amp;gt; [conditions], &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;only&lt;/span&gt; =&amp;gt; action))
    &lt;span class='ControlStructures'&gt;alias_method&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;_cache_&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;action&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;_before&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;_cache_before&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;alias_method&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;_cache_&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;action&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;_after&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,  &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;_cache_after&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;As you can see it adds a before filter and an after filter.&lt;/p&gt;

&lt;h4 id='the_before_filter_'&gt;The before filter (&lt;code&gt;_cache_before&lt;/code&gt;)&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; _cache_before(&lt;span class='Variables'&gt;conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
    &lt;span class='ControlStructures'&gt;unless&lt;/span&gt; &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_force_cache&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_skip_cache&lt;/span&gt;.nil? &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt; data &lt;span class='Operators'&gt;=&lt;/span&gt; Merb::Cache[_lookup_store(conditions)].read(&lt;span class='Variables'&gt;self&lt;/span&gt;, _parameters_and_conditions(conditions).first)
        &lt;span class='Keywords'&gt;throw&lt;/span&gt;(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;halt&lt;/span&gt;, data)
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_cached&lt;/span&gt; &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;true&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;else&lt;/span&gt;
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_cached&lt;/span&gt; &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;false&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; _lookup_store(&lt;span class='Variables'&gt;conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
    conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;store&lt;/span&gt;] &lt;span class='Operators'&gt;||&lt;/span&gt; conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;stores&lt;/span&gt;] &lt;span class='Operators'&gt;||&lt;/span&gt; default_cache_store
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;@_force_cache&lt;/code&gt; is set by the &lt;code&gt;force_cache!&lt;/code&gt; instance method which is called when eager caching (see below) &lt;code&gt;@_skip_cache&lt;/code&gt; is set by the &lt;code&gt;skip_cache!&lt;/code&gt; instance method&lt;/p&gt;

&lt;p&gt;You can override &lt;code&gt;default_cache_store&lt;/code&gt; to set a default store for your controller&lt;/p&gt;

&lt;h4 id='the_after_filter_'&gt;The after filter (&lt;code&gt;_cache_after&lt;/code&gt;)&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; _cache_after(&lt;span class='Variables'&gt;conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
    &lt;span class='ControlStructures'&gt;if&lt;/span&gt; &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_cached&lt;/span&gt; &lt;span class='Operators'&gt;==&lt;/span&gt; &lt;span class='LanguageConstants'&gt;false&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; Merb::Cache[_lookup_store(conditions)].write(&lt;span class='Variables'&gt;self&lt;/span&gt;, &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;, &lt;span class='Operators'&gt;*&lt;/span&gt;_parameters_and_conditions(conditions))
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_cache_write&lt;/span&gt; &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;true&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Pretty trivial it just writes gives the current instance of the controller to the store write method (for more details on what happens then see &lt;a href='http://gom-jabbar.org/articles/2008/12/09/merb-cache-and-its-stores'&gt;http://gom-jabbar.org/articles/2008/12/09/merb-cache-and-its-stores&lt;/a&gt;) and uses &lt;em&gt;parameters&lt;/em&gt;and_conditions(conditions) to determine which parameters and conditions to pass on to the store&lt;/p&gt;

&lt;h4 id='_parameters_and_conditionsconditions'&gt;_parameters_and_conditions(conditions)&lt;/h4&gt;

&lt;p&gt;This methods is used to determine which parameters will be passed to the cache store.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='ControlStructures'&gt;def&lt;/span&gt; _parameters_and_conditions(&lt;span class='Variables'&gt;conditions&lt;/span&gt;)
  parameters &lt;span class='Operators'&gt;=&lt;/span&gt; {}

  &lt;span class='ControlStructures'&gt;if&lt;/span&gt; &lt;span class='Variables'&gt;self&lt;/span&gt;.class.respond_to? &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;action_argument_list&lt;/span&gt;
    arguments, defaults &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;self&lt;/span&gt;.class.action_argument_list[action_name]
    arguments.inject(parameters) &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;parameters&lt;/span&gt;, &lt;span class='Variables'&gt;arg&lt;/span&gt;|
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; defaults.include?(arg.first)
        parameters[arg.first] &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;self&lt;/span&gt;.params[arg.first] &lt;span class='Operators'&gt;||&lt;/span&gt; arg.last
      &lt;span class='ControlStructures'&gt;else&lt;/span&gt;
        parameters[arg.first] &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;self&lt;/span&gt;.params[arg.first]
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
      parameters
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

  &lt;span class='ControlStructures'&gt;case&lt;/span&gt; conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;params&lt;/span&gt;]
  &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Variables'&gt;Symbol&lt;/span&gt;
    parameters[conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;params&lt;/span&gt;]] &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;self&lt;/span&gt;.params[conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;params&lt;/span&gt;]]
  &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Variables'&gt;Array&lt;/span&gt;
    conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;params&lt;/span&gt;].each &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;param&lt;/span&gt;|
      parameters[param] &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;self&lt;/span&gt;.params[param]
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

  &lt;span class='ControlStructures'&gt;return&lt;/span&gt; parameters, conditions.except(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;params&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;store&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;stores&lt;/span&gt;)
&lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It passes by default all the parameters used by merb-action-args (accessed by &lt;code&gt;self.class.action_argument_list[action_name]&lt;/code&gt;) and then uses the :params condition to determine which parameters to pass.&lt;/p&gt;

&lt;h3 id='eager_cache'&gt;eager_cache&lt;/h3&gt;

&lt;p&gt;Eager caching is one solution to the dog pile effect (see &lt;a href='http://gom-jabbar.org/articles/2008/12/15/introducing-mint-store-a-strategic-store-for-merb-cache'&gt;Introducing Mint Store&amp;#8217;s introduction&lt;/a&gt; for a quick introduction to the dog pile effect). Eager cache basically caches some actions whenever the trigger action is completed. It uses &lt;code&gt;Merb.run_later&lt;/code&gt; so as not to make the client wait. There are two &lt;code&gt;eager_cache&lt;/code&gt; methods, an instance method and a class method&lt;/p&gt;

&lt;h4 id='the_class_method'&gt;The class method&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;eager_cache(trigger_action, target = trigger_action, conditions = {}, &amp;amp;blk)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;trigger_action&lt;/code&gt; has been run, the &lt;code&gt;target&lt;/code&gt; action will be cached with the conditions sent to the store.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;target&lt;/code&gt; can be of the form &lt;code&gt;[controller, action]&lt;/code&gt; if no controller is given, the current controller is used&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;conditions accepts the following specific parameters&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:uri&lt;/code&gt; the uri of the resource you want to eager cache (it&amp;#8217;s needed by the page store but can be provided instead by a block)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:method&lt;/code&gt; the http method to use when requesting the resource to eager cache (defaults to :get)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:store&lt;/code&gt; which store to use for &lt;code&gt;eager_caching&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:params&lt;/code&gt; list of params to pass to the store when writing to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, conditions is also passed to the store, so any other supported conditions from the store can be used.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This method accepts a block that allows you setup the request (more on this later).&lt;/p&gt;

&lt;h4 id='the_instance_method'&gt;The instance method&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;eager_cache(action, conditions = {}, params = request.params.dup, env = request.env.dup, &amp;amp;blk)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;target&lt;/code&gt; can be of the form &lt;code&gt;[controller, action]&lt;/code&gt; if no controller is given, the current controller is used&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;conditions&lt;/code&gt; accepts the following specific parameters&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:uri&lt;/code&gt; the uri of the resource you want to eager cache (it&amp;#8217;s needed by the page store but can be provided instead by a block)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:method&lt;/code&gt; the http method to use when requesting the resource to eager cache (defaults to :get)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;params&lt;/code&gt; is just passed as a parameter to the block&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;env&lt;/code&gt; is used to create a new request if you do not pass a block (it&amp;#8217;s passed to &lt;code&gt;build_request&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This method accepts a block that allows you setup the request (more on this later).&lt;/p&gt;

&lt;h4 id='the_heart_of_eager_caching_the__class_method'&gt;The heart of eager caching the &lt;code&gt;eager_dispatch&lt;/code&gt; class method&lt;/h4&gt;

&lt;p&gt;This is the function that is called in the run_later block&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='ControlStructures'&gt;def&lt;/span&gt; eager_dispatch(&lt;span class='Variables'&gt;action&lt;span class='Variables'&gt;,&lt;/span&gt; params &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; env &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; blk &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;&lt;/span&gt;)
  kontroller &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='ControlStructures'&gt;if&lt;/span&gt; blk.nil?
    &lt;span class='Keywords'&gt;new&lt;/span&gt;(build_request({}, env))
  &lt;span class='ControlStructures'&gt;else&lt;/span&gt;
    result &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='ControlStructures'&gt;case&lt;/span&gt; blk.arity
      &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Numbers'&gt;0&lt;/span&gt;  &lt;span class='ControlStructures'&gt;then&lt;/span&gt;  blk[]
      &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Numbers'&gt;1&lt;/span&gt;  &lt;span class='ControlStructures'&gt;then&lt;/span&gt;  blk[params]
      &lt;span class='ControlStructures'&gt;else&lt;/span&gt;          blk[&lt;span class='Operators'&gt;*&lt;/span&gt;[params, env]]
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

    &lt;span class='ControlStructures'&gt;case&lt;/span&gt; result
    &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Variables'&gt;NilClass&lt;/span&gt;         &lt;span class='ControlStructures'&gt;then&lt;/span&gt; &lt;span class='Keywords'&gt;new&lt;/span&gt;(build_request({}, env))
    &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Variables'&gt;Hash&lt;/span&gt;, &lt;span class='Variables'&gt;Mash&lt;/span&gt;       &lt;span class='ControlStructures'&gt;then&lt;/span&gt; &lt;span class='Keywords'&gt;new&lt;/span&gt;(build_request({}, result))
    &lt;span class='ControlStructures'&gt;when&lt;/span&gt; Merb::Request    &lt;span class='ControlStructures'&gt;then&lt;/span&gt; &lt;span class='Keywords'&gt;new&lt;/span&gt;(result)
    &lt;span class='ControlStructures'&gt;when&lt;/span&gt; Merb::Controller &lt;span class='ControlStructures'&gt;then&lt;/span&gt; result
    &lt;span class='ControlStructures'&gt;else&lt;/span&gt; &lt;span class='Keywords'&gt;raise&lt;/span&gt; &lt;span class='Variables'&gt;ArgumentError&lt;/span&gt;, &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;Block to eager_cache must return nil, the env Hash, a Request object, or a Controller object&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

  kontroller.force_cache!

  kontroller._dispatch(action)

  kontroller
&lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;So as you can see the block you give is used to create the controller instance. You can either return a hash that will be used as the env for the build_request, return a request or return a controller.&lt;/p&gt;

&lt;p&gt;Once the kontroller instance is created, force_cache! is called to bypass the cache read in &lt;code&gt;_cache_before&lt;/code&gt; and the action is dispatch to the controller.&lt;/p&gt;

&lt;h4 id='examples_of_using_eager_cache'&gt;Examples of using eager_cache&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Class method:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Eager caching show and index after creating:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;class&lt;/span&gt; Articles
    cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;show&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;
    eager_cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;update&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;show&lt;/span&gt; &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;params&lt;/span&gt;|
      &lt;span class='Variables'&gt;self&lt;/span&gt;.build_request(build_url(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;article&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; params[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt;]), &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; &lt;span class='Numbers'&gt;1&lt;/span&gt;)
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    eager_cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;update&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;uri&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;/articles&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;
    eager_cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;create&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;
    eager_cache(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;create&lt;/span&gt;, [&lt;span class='Variables'&gt;Timeline&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;]) {{ &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;uri&lt;/span&gt; =&amp;gt; build_url(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;timelines&lt;/span&gt;)}}
    eager_cache(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;update&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;show&lt;/span&gt;) &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;params&lt;/span&gt;| 
      build_request(build_url(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;article&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; params[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt;]), &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; params[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt;])
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Let&amp;#8217;s analyse them one by one:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  eager_cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;update&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;uri&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;/articles&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;When the update action is completed, a get request to :index with &amp;#8216;/articles&amp;#8217; uri will be cached (if you use the page store, this will be stored in &amp;#8216;/articles.html&amp;#8217;)&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  eager_cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;create&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This does the same after the create action but uses the fact that if no uri is given, the current uri is used but the http method used is get. This defaults work well with standard resource controller&amp;#8230;.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  eager_cache(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;create&lt;/span&gt;, [&lt;span class='Variables'&gt;Timeline&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;index&lt;/span&gt;]) {{ &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;uri&lt;/span&gt; =&amp;gt; build_url(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;timelines&lt;/span&gt;)}}
&lt;/pre&gt;
&lt;p&gt;This line is equivalent to &lt;code&gt;eager_cache(:create, [Timeline, :index]) { build_request(build_url(:timelines))}&lt;/code&gt; but is a bit more readable in my oppinion. It shows how you can use the url generation for specifying the uri.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  eager_cache(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;update&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;show&lt;/span&gt;) &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;params&lt;/span&gt;| 
    build_request(build_url(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;article&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; params[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt;]), &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; params[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;id&lt;/span&gt;])
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This eager caches the show action for the updated object. It&amp;#8217;s possible to do this, but I think using the instance method (see below) for this task is a cleaner approach.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Instance method:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want to cache the show action for a newly created article, you&amp;#8217;ll need to use the instance_method.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; create(&lt;span class='Variables'&gt;article&lt;/span&gt;)
    &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;article&lt;/span&gt; &lt;span class='Operators'&gt;=&lt;/span&gt; Article.new(article)
    &lt;span class='ControlStructures'&gt;if&lt;/span&gt; &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;article&lt;/span&gt;.save
      eager_cache &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;show&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;uri&lt;/span&gt; =&amp;gt; url(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;article&lt;/span&gt;, &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;article&lt;/span&gt;)
      redirect resource(&lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;article&lt;/span&gt;), &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;message&lt;/span&gt; =&amp;gt; {&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;notice&lt;/span&gt; =&amp;gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;Article was successfully created&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}
    &lt;span class='ControlStructures'&gt;else&lt;/span&gt;
&lt;span class='Comments'&gt;      &lt;span class='Comments'&gt;#&lt;/span&gt;....&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;What I usually do is create a common private method (e.g. &lt;code&gt;eager_cache_article&lt;/code&gt;) that I call from update and create.&lt;/p&gt;

&lt;h3 id='fetch_partial'&gt;fetch_partial&lt;/h3&gt;

&lt;p&gt;It caches the result of a partial.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='ControlStructures'&gt;def&lt;/span&gt; fetch_partial(&lt;span class='Variables'&gt;template&lt;span class='Variables'&gt;,&lt;/span&gt; opts&lt;span class='Operators'&gt;=&lt;/span&gt;&lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
   template_id &lt;span class='Operators'&gt;=&lt;/span&gt; template.to_s
   &lt;span class='ControlStructures'&gt;if&lt;/span&gt; template_id &lt;span class='Operators'&gt;=~&lt;/span&gt; &lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;%r{&lt;/span&gt;^/&lt;span class='RegularExpressions'&gt;}&lt;/span&gt;&lt;/span&gt;
     template_path &lt;span class='Operators'&gt;=&lt;/span&gt; File.dirname(template_id) &lt;span class='Operators'&gt;/&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;_&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;&lt;span class='Strings'&gt;File&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;basename&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;(&lt;/span&gt;template_id&lt;span class='Strings'&gt;)&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class='ControlStructures'&gt;else&lt;/span&gt;
     kontroller &lt;span class='Operators'&gt;=&lt;/span&gt; (m &lt;span class='Operators'&gt;=&lt;/span&gt; template_id.match(&lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class='RegularExpressions'&gt;.*&lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;(&lt;/span&gt;?=&lt;span class='CharacterConstants'&gt;\/&lt;/span&gt;&lt;span class='RegularExpressions'&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;/&lt;/span&gt;&lt;/span&gt;)) &lt;span class='Operators'&gt;?&lt;/span&gt; m[&lt;span class='Numbers'&gt;0&lt;/span&gt;] : controller_name
     template_id &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;_&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;&lt;span class='Strings'&gt;File&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;basename&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;(&lt;/span&gt;template_id&lt;span class='Strings'&gt;)&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
   &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

   unused, template_key &lt;span class='Operators'&gt;=&lt;/span&gt; _template_for(template_id, opts.delete(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;format&lt;/span&gt;) &lt;span class='Operators'&gt;||&lt;/span&gt; content_type, kontroller, template_path)
   template_key.gsub!(File.expand_path(Merb.root),&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;)

   fetch_proc &lt;span class='Operators'&gt;=&lt;/span&gt; lambda { partial(template, opts) }
   params_for_cache &lt;span class='Operators'&gt;=&lt;/span&gt; opts.delete(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;params_for_cache&lt;/span&gt;) &lt;span class='Operators'&gt;||&lt;/span&gt; opts.dup

   concat(Merb::Cache[_lookup_store(conditions)].fetch(template_key, params_for_cache, conditions, &lt;span class='Operators'&gt;&amp;amp;&lt;/span&gt;fetch_proc), fetch_proc.binding)
 &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It is called the same as a partial would except that you can add a conditions hash at the end that will be passed to the cache store.&lt;/p&gt;

&lt;h5 id='caveat'&gt;Caveat&lt;/h5&gt;

&lt;p&gt;If you call &lt;code&gt;fetch_partial&lt;/code&gt; with parameters that are instance of model it will fail. Currently the cache stores available convert the parameters to string using to_s. And &lt;code&gt;@model.to_s&lt;/code&gt; by default will give you something like &lt;code&gt;#&amp;lt;Article:0x255ca9c&amp;gt;&lt;/code&gt;&amp;#8230;&lt;/p&gt;

&lt;p&gt;So instead, you can either override to_s in your model (I don&amp;#8217;t recommend it, it doesn&amp;#8217;t express your intent clearly and will probably be hell to maintain later) or you can pass the &lt;code&gt;:params_for_cache&lt;/code&gt; option which will be used by your cache store.&lt;/p&gt;

&lt;p&gt;Another possibility is to create a specific strategy store for your project that takes care of converting your models. It&amp;#8217;s useful if you use a technique like the one explained by Tobias Lutke in &lt;a href='http://blog.leetsoft.com/2007/5/22/the-secret-to-memcached'&gt;http://blog.leetsoft.com/2007/5/22/the-secret-to-memcached&lt;/a&gt;, you can create a strategy store that is in charge of finding the current store version (and passing it along as a parameter) from the parameters passed to it.&lt;/p&gt;

&lt;p&gt;After this article, you might want to check &lt;a href='http://gom-jabbar.org/articles/2008/12/09/merb-cache-and-its-stores'&gt;Merb-cache and its stores&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=5dVAVmmS"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=5dVAVmmS" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=wXNCKcyk"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=Mt1IKKbW"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=Mt1IKKbW" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/E1h8y1wCicc" height="1" width="1"/&gt;</description><pubDate>Fri, 19 Dec 2008 23:05:31 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/19/merb-cache-s-methods</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Introducing nginx_accept_language_module</title><link>http://gom-jabbar.org/articles/2008/12/17/introducing-nginx_accept_language_module</link><description>&lt;h3 id='what_does_it_do'&gt;What does it do?&lt;/h3&gt;

&lt;p&gt;This module parses the Accept-Language header and gives the most suitable locale for the user from a list of supported locales from your website.&lt;/p&gt;

&lt;h3 id='why_did_i_create_it'&gt;Why did I create it?&lt;/h3&gt;

&lt;p&gt;I’m using page caching with merb on a multi-lingual website and I needed a way to serve the correct language page from the cache For multi-lingual page caching see the cache branch of the merb_global fork at &amp;lt;http://github.com/giom/merb_global&amp;gt; , I&amp;#8217;ll post a write-up about this later.&lt;/p&gt;

&lt;h3 id='syntax'&gt;Syntax:&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;set_from_accept_language $lang en ja pl;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$lang&lt;/code&gt; is the variable in which to store the locale&lt;/li&gt;

&lt;li&gt;&lt;code&gt;en ja pl&lt;/code&gt; are the locales supported by your website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If none of the locales from accept_language is available on your website, it sets the variable to the first locale of your website’s supported locales (in this case en)&lt;/p&gt;

&lt;h5 id='caveat'&gt;Caveat&lt;/h5&gt;

&lt;p&gt;It currently assumes that the accept-language is sorted by quality values (from my tests it’s the case for safari, firefox, opera and ie) and discards q (see &amp;lt;http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html&amp;gt;). In the situation where I’m using the module, this assumption works… but buyer beware :-)&lt;/p&gt;

&lt;h3 id='example_configuration'&gt;Example configuration&lt;/h3&gt;

&lt;p&gt;If you have different subdomains for each languages &lt;pre class='pastels_on_dark'&gt;
&lt;span class='LanguageConstants'&gt;server&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
    &lt;span class='LanguageConstants'&gt;listen&lt;/span&gt; &lt;span class='Numbers'&gt;8&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
    &lt;span class='LanguageConstants'&gt;server_name&lt;/span&gt; your_domain.com&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
    set_from_accept_language $lang en ja zh&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
    &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt; ^/&lt;span class='CharacterConstants'&gt;(&lt;/span&gt;.*&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; http://$lang.your_domain.com redirect&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
&lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Or you could do something like this, redirecting people coming to &amp;#8217;/&amp;#8217; to /en (or /pt)&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='LanguageConstants'&gt;location&lt;/span&gt; / &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
    set_from_accept_language $lang pt en&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt; $request_uri &lt;span class='RegularExpressions'&gt;~&lt;/span&gt; ^/$ &lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt; ^/$ /$lang redirect&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
&lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;h3 id='where_to_get_it'&gt;Where to get it?&lt;/h3&gt;

&lt;p&gt;It&amp;#8217;s available on github at &lt;a href='http://github.com/giom/nginx_accept_language_module'&gt;http://github.com/giom/nginx_accept_language_module&lt;/a&gt;&lt;/p&gt;

&lt;h3 id='installation'&gt;Installation&lt;/h3&gt;

&lt;p&gt;Download the module source from github: &lt;a href='http://github.com/giom/nginx_accept_language_module'&gt;http://github.com/giom/nginx_accept_language_module&lt;/a&gt; or clone it with &lt;code&gt;git clone git://github.com/giom/nginx_accept_language_module.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Unpack, and then compile nginx with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;`./configure --add-module=path/to/nginx_accept_language_module`&lt;/code&gt;&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=H0mbrMvc"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=H0mbrMvc" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=AMLl4JKO"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=aeVXWKBY"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=aeVXWKBY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/luCHFNstSG0" height="1" width="1"/&gt;</description><pubDate>Wed, 17 Dec 2008 08:38:28 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/17/introducing-nginx_accept_language_module</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Introducing Mint Store a strategic store for merb</title><link>http://gom-jabbar.org/articles/2008/12/15/introducing-mint-store-a-strategic-store-for-merb-cache</link><description>&lt;p&gt;If you&amp;#8217;re coming here for the first time, be sure to check two other articles I wrote on merb-cache&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://gom-jabbar.org/articles/2008/12/19/merb-cache-s-methods'&gt;Merb-cache&amp;#8217;s method&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://gom-jabbar.org/articles/2008/12/09/merb-cache-and-its-stores'&gt;Merb-cache and its stores&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id='what_is_the_dog_pile_effect'&gt;What is the dog pile effect?&lt;/h4&gt;

&lt;p&gt;Memcache is great when you want to cache some rather heavy queries. For example, one query I cache on a project looks like this:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
	&lt;span class='Keywords'&gt;select&lt;/span&gt; answers.question_id, answers.question_choice_id, COUNT(*) AS count, question_choices.text &lt;span class='Keywords'&gt;from&lt;/span&gt; answers &lt;span class='Keywords'&gt;INNER JOIN&lt;/span&gt; question_choices &lt;span class='Keywords'&gt;ON &lt;/span&gt;question_choice_id = question_choices.id &lt;span class='Keywords'&gt;WHERE&lt;/span&gt; answers.&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;`&lt;/span&gt;question_id`&lt;/span&gt; = &lt;span class='Numbers'&gt;1&lt;/span&gt; &lt;span class='Keywords'&gt;AND&lt;/span&gt; answers.&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;`&lt;/span&gt;media_id`&lt;/span&gt; = &lt;span class='Numbers'&gt;1&lt;/span&gt; &lt;span class='Keywords'&gt;GROUP BY&lt;/span&gt; answers.question_choice_id 
&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s a rather long query when there are a lot of rows so it makes sense to cache it. Now, I don&amp;#8217;t want to always serve the same data so I use the expiration feature of memcache (&lt;code&gt;:expire_in&lt;/code&gt; in merb-cache).&lt;/p&gt;

&lt;p&gt;But what happens when some huge traffic comes and your cache expires? If the data ir quick to generate it&amp;#8217;s not a big problem but it it uses a rather long query and take a few seconds then while the thread that got the first cache miss will recalculate the data, other requests will get a cache miss and also recalculate the data. And this added calculation might slow down the whole system (or your db server) leading you to a death spiral&amp;#8230;&lt;/p&gt;

&lt;h4 id='mint_store'&gt;Mint Store&lt;/h4&gt;

&lt;p&gt;To solve this problem, Glenn Franxman released MintCache a caching engine for Django &lt;a href='http://www.djangosnippets.org/snippets/155/'&gt;http://www.djangosnippets.org/snippets/155/&lt;/a&gt;. The Disqus team then released another implementation of MintCache &lt;a href='http://blog.disqus.net/2008/06/11/mintcache-simple-version/'&gt;http://blog.disqus.net/2008/06/11/mintcache-simple-version/&lt;/a&gt; Mint Store is a port of this work to merb-cache.&lt;/p&gt;

&lt;p&gt;It solves the problem by adding the time by adding some metadata: the stale date and if the cache is currently being refreshed. When doing a read request, it checks if the stale date is passed and if it&amp;#8217;s passed sets refreshed to true and returns nil.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s probably easier to understand looking at the code (I need to get better at explaining this kind of stuff)&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; read(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      packed_data &lt;span class='Operators'&gt;=&lt;/span&gt; store_read(key, parameters)
      &lt;span class='ControlStructures'&gt;return&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt; &lt;span class='ControlStructures'&gt;unless&lt;/span&gt; packed_data
      
      data, refresh_time, refreshed &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Operators'&gt;*&lt;/span&gt;packed_data
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; &lt;span class='Operators'&gt;!&lt;/span&gt;refreshed &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Time.now &lt;span class='Operators'&gt;&amp;gt;&lt;/span&gt; refresh_time) 
        write(key, data, parameters, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;expire_in&lt;/span&gt; =&amp;gt; &lt;span class='Numbers'&gt;0&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;refreshed&lt;/span&gt; =&amp;gt; &lt;span class='LanguageConstants'&gt;true&lt;/span&gt;)
        &lt;span class='ControlStructures'&gt;return&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
      data
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; get_metadata_and_normalize!(&lt;span class='Variables'&gt;conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      expire_in &lt;span class='Operators'&gt;=&lt;/span&gt; conditions.delete(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;expire_in&lt;/span&gt;) &lt;span class='Operators'&gt;||&lt;/span&gt; options[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;expire_in&lt;/span&gt;]
      refreshed &lt;span class='Operators'&gt;=&lt;/span&gt; conditions.delete(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;refreshed&lt;/span&gt;)
      conditions[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;expire_in&lt;/span&gt;] &lt;span class='Operators'&gt;=&lt;/span&gt; expire_in &lt;span class='Operators'&gt;+&lt;/span&gt; (conditions.delete(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;mint_delay&lt;/span&gt;) &lt;span class='Operators'&gt;||&lt;/span&gt; options[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;mint_delay&lt;/span&gt;])
      [Time.now &lt;span class='Operators'&gt;+&lt;/span&gt;  expire_in, refreshed]
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Compared to Disqus&amp;#8217; MintCache, I added two features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you use fetch (and provide a block), if the cache is stale, Mint Store will return the stale cache and update the cache (with the result of executing the provided block) after the request has been served using &lt;code&gt;Merb.run_later&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Deletion will just mark the cache as stale which will cause the next fetch to repopulate the cache. (This can be disabled, see the initialization options)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id='important_note_read_and_fetch'&gt;Important Note: Read and Fetch&lt;/h5&gt;

&lt;p&gt;Read returns nil the first time the cache becomes stale and then returns the stale cache for &lt;code&gt;:mint_delay&lt;/code&gt; seconds. So on the contrary to using fetch where none of the clients will be penalized, if you use read, you will penalize one clients who will have to wait for the cache to be refreshed before his request is served. (&lt;code&gt;fetch_fragment&lt;/code&gt; and &lt;code&gt;fetch_partial&lt;/code&gt; from merb-cache both use &lt;code&gt;fetch&lt;/code&gt;)&lt;/p&gt;

&lt;h4 id='initialization_options'&gt;Initialization Options&lt;/h4&gt;

&lt;p&gt;Mint Store accepts several initialization options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Behaviour options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:force_delete&lt;/code&gt; if set to true, delete will just delete the data from the cache&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:need_expire_in&lt;/code&gt; if set to true, writable? will return false if the &lt;code&gt;:expire_in&lt;/code&gt; condition is not present. If you are going to use MintStore with the AdHocStore it makes sense to set it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Default values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:mint_delay&lt;/code&gt; : the difference between the stale date (that you provide by &lt;code&gt;:expire_in&lt;/code&gt;) and the real &lt;code&gt;:expire_in&lt;/code&gt; given to memcached (default: 30s)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:refresh_delay&lt;/code&gt; : the &lt;code&gt;:expire_in&lt;/code&gt; value given to memcached while regenerating the cache (can set to 0 if you want memcache to never expire the stale cache while waiting for it to be refreshed)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;:expire_in&lt;/code&gt; : default value for the stale date if not provided (default: 300s)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: setting the options&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
        register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;memcached_store&lt;/span&gt;, Merb::Cache::MemcachedStore)
        register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;mint_store&lt;/span&gt;, Merb::Cache::MintStore[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;memcached_store&lt;/span&gt;], &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;need_expire_in&lt;/span&gt; =&amp;gt; &lt;span class='LanguageConstants'&gt;true&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;refresh_delay&lt;/span&gt; =&amp;gt; &lt;span class='Numbers'&gt;0&lt;/span&gt;)
&lt;/pre&gt;
&lt;h4 id='where_to_get_it'&gt;Where to get it&lt;/h4&gt;

&lt;p&gt;You can get it fresh from github at &lt;a href='http://github.com/giom/mint_store'&gt;http://github.com/giom/mint_store&lt;/a&gt; Or install it as a gem with: &lt;code&gt;gem install giom-mint_store --source http://gems.github.com&lt;/code&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=B0g7fI6z"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=B0g7fI6z" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=oJSCZy3o"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=ZZQvtomN"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=ZZQvtomN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/xwPoylp6fAk" height="1" width="1"/&gt;</description><pubDate>Mon, 15 Dec 2008 12:04:00 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/15/introducing-mint-store-a-strategic-store-for-merb-cache</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Nginx configuration for merb with page caching (file store)</title><link>http://gom-jabbar.org/articles/2008/12/14/example-nginx-configuration-for-merb-with-page-caching-using-the-file-store</link><description>&lt;p&gt;This is the nginx configuration I use for this blog. One thing to note is that on the contrary to the rails convention of putting the cache in public, I like to segregate it in the public/page_cache directory.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='LanguageConstants'&gt;upstream&lt;/span&gt; seshat &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
  &lt;span class='LanguageConstants'&gt;server&lt;/span&gt; &lt;span class='Numbers'&gt;1&lt;/span&gt;&lt;span class='Numbers'&gt;2&lt;/span&gt;&lt;span class='Numbers'&gt;7&lt;/span&gt;.&lt;span class='Numbers'&gt;0&lt;/span&gt;.&lt;span class='Numbers'&gt;0&lt;/span&gt;.&lt;span class='Numbers'&gt;1&lt;/span&gt;:&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
  &lt;span class='LanguageConstants'&gt;server&lt;/span&gt; &lt;span class='Numbers'&gt;1&lt;/span&gt;&lt;span class='Numbers'&gt;2&lt;/span&gt;&lt;span class='Numbers'&gt;7&lt;/span&gt;.&lt;span class='Numbers'&gt;0&lt;/span&gt;.&lt;span class='Numbers'&gt;0&lt;/span&gt;.&lt;span class='Numbers'&gt;1&lt;/span&gt;:&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='Numbers'&gt;4&lt;/span&gt;&lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
&lt;span class='CharacterConstants'&gt;}&lt;/span&gt;


&lt;span class='Comments'&gt;# Redirecting all www.gom-jabbar.org trafic to gom-jabbar.org&lt;/span&gt;
&lt;span class='LanguageConstants'&gt;server&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
 &lt;span class='LanguageConstants'&gt;listen&lt;/span&gt;       &lt;span class='Numbers'&gt;8&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
 &lt;span class='LanguageConstants'&gt;server_name&lt;/span&gt;  www.gom-jabbar.org&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
 &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt; ^/&lt;span class='CharacterConstants'&gt;(&lt;/span&gt;.*&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; http://gom-jabbar.org permanent&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;

&lt;span class='CharacterConstants'&gt;}&lt;/span&gt;


&lt;span class='Comments'&gt;# the server directive is nginx's virtual host directive.&lt;/span&gt;
 &lt;span class='LanguageConstants'&gt;server&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
   &lt;span class='Comments'&gt;# port to listen on. Can also be set to an IP:PORT&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;listen&lt;/span&gt;       &lt;span class='Numbers'&gt;8&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;

   &lt;span class='Comments'&gt;# sets the domain[s] that this vhost server requests for&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;server_name&lt;/span&gt;  gom-jabbar.org&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;

   &lt;span class='Comments'&gt;# vhost specific access log&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;access_log&lt;/span&gt;      /var/log/nginx/seshat.&lt;span class='LanguageConstants'&gt;access_log&lt;/span&gt; main&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;error_log&lt;/span&gt;       /var/log/nginx/seshat.&lt;span class='LanguageConstants'&gt;error_log&lt;/span&gt; info&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;


   &lt;span class='Comments'&gt;#Set the max size for file uploads to 1Mb&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;client_max_body_size&lt;/span&gt;  &lt;span class='Numbers'&gt;1&lt;/span&gt;M&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;

   &lt;span class='LanguageConstants'&gt;root&lt;/span&gt; /sites/seshat_blog/public&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;set&lt;/span&gt; $cache_path $document_root/page_cache&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   
   index  index.html&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   
   &lt;span class='Comments'&gt;# this rewrites all the requests to the maintenance.html&lt;/span&gt;
   &lt;span class='Comments'&gt;# page if it exists in the doc root. This is for capistrano's&lt;/span&gt;
   &lt;span class='Comments'&gt;# disable web task&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;-f $document_root/system/maintenance.html&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt;  ^&lt;span class='CharacterConstants'&gt;(&lt;/span&gt;.*&lt;span class='CharacterConstants'&gt;)&lt;/span&gt;$  /system/maintenance.html last&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
   
   &lt;span class='LanguageConstants'&gt;location&lt;/span&gt; / &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;

     &lt;span class='LanguageConstants'&gt;proxy_set_header&lt;/span&gt;  X-Real-IP  $remote_addr&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;proxy_set_header&lt;/span&gt;  X-Forwarded-For $proxy_add_x_forwarded_for&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;proxy_set_header&lt;/span&gt;  Host $http_host&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;proxy_redirect&lt;/span&gt;    false&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;

     &lt;span class='Comments'&gt;# The next two if blocks tell nginx to look for the cache&lt;/span&gt;
     &lt;span class='Comments'&gt;# serve it if it exists&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;-f $cache_path$uri.html&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;.*&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; /cache$&lt;span class='Numbers'&gt;1&lt;/span&gt;.html &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;

     &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;-f $cache_path$uri&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;.*&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; /cache$&lt;span class='Numbers'&gt;1&lt;/span&gt; &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
     
     &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;-f $cache_path$&lt;span class='CharacterConstants'&gt;{&lt;/span&gt;uri&lt;span class='CharacterConstants'&gt;}&lt;/span&gt;index.html&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;rewrite&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;.*&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; /cache$&lt;span class='Numbers'&gt;1&lt;/span&gt;/index.html &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;

     &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;!-f $request_filename&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;proxy_pass&lt;/span&gt; http://seshat&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
     &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
   &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
   
   &lt;span class='Comments'&gt;# Add expires header for static content&lt;/span&gt;
   &lt;span class='Comments'&gt;# See Steve Souders - High Performance Web Sites rule #3&lt;/span&gt;
   &lt;span class='Comments'&gt;# Normally when I add this, I also bundle all my css, javascript&lt;/span&gt;
   &lt;span class='Comments'&gt;# with yuicompressor, and add the git commit hash&lt;/span&gt;
   &lt;span class='Comments'&gt;# of those files to their name&lt;/span&gt;
   &lt;span class='Comments'&gt;# I haven't done it yet with this blog though&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;location&lt;/span&gt; &lt;span class='RegularExpressions'&gt;~&lt;/span&gt;* &lt;span class='RegularExpressions'&gt;\.(js|css|jpg|jpeg|gif|png|svg)$ &lt;/span&gt;&lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;if&lt;/span&gt; &lt;span class='CharacterConstants'&gt;(&lt;/span&gt;-f $request_filename&lt;span class='CharacterConstants'&gt;)&lt;/span&gt; &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
           &lt;span class='LanguageConstants'&gt;expires&lt;/span&gt;      max&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
       &lt;span class='LanguageConstants'&gt;break&lt;/span&gt;&lt;span class='CharacterConstants'&gt;;&lt;/span&gt; 
     &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;  
   &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;

   &lt;span class='LanguageConstants'&gt;error_page&lt;/span&gt;  &lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt; &lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='Numbers'&gt;2&lt;/span&gt; &lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='Numbers'&gt;3&lt;/span&gt; &lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;&lt;span class='Numbers'&gt;4&lt;/span&gt; /&lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;x.html&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   &lt;span class='LanguageConstants'&gt;location&lt;/span&gt; = /&lt;span class='Numbers'&gt;5&lt;/span&gt;&lt;span class='Numbers'&gt;0&lt;/span&gt;x.html &lt;span class='CharacterConstants'&gt;{&lt;/span&gt;
     &lt;span class='LanguageConstants'&gt;root&lt;/span&gt;   html&lt;span class='CharacterConstants'&gt;;&lt;/span&gt;
   &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
 &lt;span class='CharacterConstants'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;My merb-cache setup looks like this:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  dependency &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;merb-cache&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;, merb_gems_version &lt;span class='ControlStructures'&gt;do &lt;/span&gt;
    Merb::Cache.setup &lt;span class='ControlStructures'&gt;do&lt;/span&gt;
      register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;blog_fragment_store&lt;/span&gt;, Merb::Cache::FileStore, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;dir&lt;/span&gt; =&amp;gt; Merb.root &lt;span class='Operators'&gt;/&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;cache&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class='Operators'&gt;/&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;fragments&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;)
      register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;blog_page_store&lt;/span&gt;, Merb::Cache::PageStore[Merb::Cache::FileStore], &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;dir&lt;/span&gt; =&amp;gt; Merb.root &lt;span class='Operators'&gt;/&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;public&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class='Operators'&gt;/&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;page_cache&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;)
      register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;default&lt;/span&gt;, Merb::Cache::AdhocStore[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;blog_page_store&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;blog_fragment_store&lt;/span&gt;])
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=uiGb67TK"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=uiGb67TK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=51weEbgS"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=ZFTGURbY"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=ZFTGURbY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/badW-_hccGs" height="1" width="1"/&gt;</description><pubDate>Sun, 14 Dec 2008 03:55:20 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/14/example-nginx-configuration-for-merb-with-page-caching-using-the-file-store</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Merb-cache and its stores</title><link>http://gom-jabbar.org/articles/2008/12/09/merb-cache-and-its-stores</link><description>&lt;p&gt;I&amp;#8217;ve been playing around quite a lot with merb-cache so I thought I would write a bit about merb-cache to help others. I haven&amp;#8217;t written many tutorials before so I might err too much on the side of over-explaining things. So please, tell me if you liked this article&amp;#8230; and if you see any fault in my english, I&amp;#8217;d be very glad to learn about them (3 years in japan pretty much destroyed my english).&lt;/p&gt;

&lt;p&gt;For a basic introduction to merb-cache, you should read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://github.com/wycats/merb/tree/1.0.x/merb-cache/README'&gt;http://github.com/wycats/merb/tree/1.0.x/merb-cache/README&lt;/a&gt; Nice short tutorial (and more uptodate)&lt;/li&gt;

&lt;li&gt;&lt;a href='http://merbunity.com/tutorials/15'&gt;http://merbunity.com/tutorials/15&lt;/a&gt; Goes into more details on the ideas that guided merb-cache&amp;#8217;s design (the examples are the same as above)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might also want to first read another article in the serie &lt;a href='http://gom-jabbar.org/articles/2008/12/19/merb-cache-s-methods'&gt;Merb-cache&amp;#8217;s methods&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this first part, I&amp;#8217;ll describe the different stores available, in which situations they kick in and important remarks about there usage. I&amp;#8217;ll use a top down approach and start with the strategy stores.&lt;/p&gt;

&lt;p&gt;There is a &lt;a href='#summary'&gt;quick summary/cheat sheet at the end&amp;#8230;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id='the_strategy_stores'&gt;The Strategy Stores&lt;/h1&gt;

&lt;h2 id='the_adhocstore'&gt;The AdHocStore&lt;/h2&gt;

&lt;p&gt;Used to select the most appropriate store.&lt;/p&gt;

&lt;h4 id='conditions_for_usage_'&gt;Conditions for usage (&lt;code&gt;writable?&lt;/code&gt;)&lt;/h4&gt;

&lt;p&gt;If you look at its &lt;code&gt;writable?&lt;/code&gt; method&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; writable?(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.capture_first {|&lt;span class='Variables'&gt;s&lt;/span&gt;| s.writable?(key, parameters, conditions)}
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It looks for the first store in the list that is &lt;code&gt;writable?&lt;/code&gt;&lt;/p&gt;

&lt;h4 id='writing'&gt;Writing&lt;/h4&gt;

&lt;p&gt;Same thing, for the write method:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; write(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; data &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.capture_first {|&lt;span class='Variables'&gt;s&lt;/span&gt;| s.write(key, data, parameters, conditions)}
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;h5 id='important_note'&gt;Important note&lt;/h5&gt;

&lt;p&gt;Notice that the order is important, when setting the Adhoc store up the stores you give should be given in the order of the least likely to the most likely to work (meaning writable? true)&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
	register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;correct&lt;/span&gt;, Merb::Cache::AdhocStore[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;page_store&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;action_store&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;fragment_store&lt;/span&gt;])
	register(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;wrong&lt;/span&gt;,   Merb::Cache::AdhocStore[&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;action_store&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;page_store&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;fragment_store&lt;/span&gt;])
&lt;/pre&gt;
&lt;p&gt;if you use the &lt;code&gt;:wrong&lt;/code&gt; adhoc store, the page store will never be triggered.&lt;/p&gt;

&lt;h2 id='the_pagestore'&gt;The PageStore:&lt;/h2&gt;

&lt;p&gt;Used to cache the result of a complete page so as to use it directly in nginx (or other server you might have) without hitting the merb application at all (much faster).&lt;/p&gt;

&lt;h4 id='conditions_for_usage_'&gt;Conditions for usage (&lt;code&gt;writable?&lt;/code&gt;)&lt;/h4&gt;

&lt;p&gt;Same here, let&amp;#8217;s look at its &lt;code&gt;writable?&lt;/code&gt; method&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; writable?(&lt;span class='Variables'&gt;dispatch&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; Merb::Controller &lt;span class='Operators'&gt;===&lt;/span&gt; dispatch &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt; dispatch.request.method &lt;span class='Operators'&gt;==&lt;/span&gt; &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;get&lt;/span&gt; &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class='Operators'&gt;!&lt;/span&gt;dispatch.request.uri.nil? &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='Operators'&gt;!&lt;/span&gt;dispatch.request.uri.empty? &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class='Operators'&gt;!&lt;/span&gt;conditions.has_key?(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;if&lt;/span&gt;) &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='Operators'&gt;!&lt;/span&gt;conditions.has_key?(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;unless&lt;/span&gt;) &lt;span class='Operators'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          query_string_present?(dispatch)
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.any? {|&lt;span class='Variables'&gt;s&lt;/span&gt;| s.writable?(normalize(dispatch), parameters, conditions)}
      &lt;span class='ControlStructures'&gt;else&lt;/span&gt;
        &lt;span class='LanguageConstants'&gt;false&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; query_string_present?(&lt;span class='Variables'&gt;dispatch&lt;/span&gt;)
      dispatch.request.env[&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;REQUEST_URI&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class='Operators'&gt;==&lt;/span&gt; dispatch.request.uri
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It only accepts controllers that received a get request that have no query string parameters (e.g. ?q=z) and doesn&amp;#8217;t cache any actions that has a if or unless conditions (e.g. cache :show, :unless =&amp;gt; :logged_in?)&lt;/p&gt;

&lt;h4 id='writing'&gt;Writing&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; normalize(&lt;span class='Variables'&gt;dispatch&lt;/span&gt;)
      key &lt;span class='Operators'&gt;=&lt;/span&gt; dispatch.request.uri.split(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;?&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;).first
      key &lt;span class='Operators'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;index&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class='ControlStructures'&gt;if&lt;/span&gt; key &lt;span class='Operators'&gt;=~&lt;/span&gt; &lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class='RegularExpressions'&gt;&lt;span class='CharacterConstants'&gt;\/&lt;/span&gt;$&lt;/span&gt;&lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;/&lt;/span&gt;&lt;/span&gt;
      key &lt;span class='Operators'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;.&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;dispatch&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;content_type&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class='ControlStructures'&gt;unless&lt;/span&gt; key &lt;span class='Operators'&gt;=~&lt;/span&gt; &lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class='RegularExpressions'&gt;&lt;span class='CharacterConstants'&gt;\.&lt;/span&gt;&lt;span class='CharacterConstants'&gt;\w&lt;/span&gt;&lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;{&lt;/span&gt;2,6&lt;span class='RegularExpressions'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class='RegularExpressions'&gt;&lt;span class='RegularExpressions'&gt;/&lt;/span&gt;&lt;/span&gt;
      key
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

	&lt;span class='ControlStructures'&gt;def&lt;/span&gt; write(&lt;span class='Variables'&gt;dispatch&lt;span class='Variables'&gt;,&lt;/span&gt; data &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; writable?(dispatch, parameters, conditions)
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.capture_first {|&lt;span class='Variables'&gt;s&lt;/span&gt;| s.write(normalize(dispatch), data &lt;span class='Operators'&gt;||&lt;/span&gt; dispatch.body, {}, conditions)}
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;normalize&lt;/code&gt; method that is used to generate a key, creates a key depending on the uri and content_type. The &lt;code&gt;write&lt;/code&gt; method doesn&amp;#8217;t send any parameters (which would be encoded as part of the key by memcached_store and file_store), so the page cache key doesn&amp;#8217;t depend on any parameters not encoded in the uri (consistent with writable? policy of only returning true when there are no query string parameters)&lt;/p&gt;

&lt;h5 id='important_note'&gt;Important note&lt;/h5&gt;

&lt;p&gt;PageStore doesn&amp;#8217;t support reading as it&amp;#8217;s intended for use with a server like nginx (I&amp;#8217;ll give some examples of nginx configuration in a later blog post). So &lt;code&gt;read&lt;/code&gt; always returns &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; read(&lt;span class='Variables'&gt;dispatch&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
    &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;h2 id='the_actionstore'&gt;The ActionStore&lt;/h2&gt;

&lt;p&gt;Used to cache actions that have parameters or conditions for caching. Because the request will have to hit the merb application (and go through routing), it&amp;#8217;s much slower than page store caching.&lt;/p&gt;

&lt;h4 id='conditions_for_usage_'&gt;Conditions for usage (&lt;code&gt;writable?&lt;/code&gt;)&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; writable?(&lt;span class='Variables'&gt;dispatch&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;case&lt;/span&gt; dispatch
      &lt;span class='ControlStructures'&gt;when&lt;/span&gt; Merb::Controller
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.any?{|&lt;span class='Variables'&gt;s&lt;/span&gt;| s.writable?(normalize(dispatch), parameters, conditions)}
      &lt;span class='ControlStructures'&gt;else&lt;/span&gt; &lt;span class='LanguageConstants'&gt;false&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;As long as dispatch is a controller (meaning that the store is used by the cache controller method, e.g. &lt;code&gt;cache :show&lt;/code&gt;) and of course that it has a substore for which &lt;code&gt; store.writable?(normalize(dispatch), parameters, conditions)&lt;/code&gt; return true (but this is common to all strategic stores), it will be writable.&lt;/p&gt;

&lt;h4 id='writing'&gt;Writing&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; write(&lt;span class='Variables'&gt;dispatch&lt;span class='Variables'&gt;,&lt;/span&gt; data &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; writable?(dispatch, parameters, conditions)
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.capture_first {|&lt;span class='Variables'&gt;s&lt;/span&gt;| s.write(normalize(dispatch), data &lt;span class='Operators'&gt;||&lt;/span&gt; dispatch.body, parameters, conditions)}
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

   &lt;span class='ControlStructures'&gt;def&lt;/span&gt; normalize(&lt;span class='Variables'&gt;dispatch&lt;/span&gt;)
      &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;dispatch&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;name&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;#&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;dispatch&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;action_name&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class='ControlStructures'&gt;unless&lt;/span&gt; dispatch.class.name.blank? &lt;span class='Operators'&gt;||&lt;/span&gt; dispatch.action_name.blank?
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The key only depends on the controller and action but the action store also passes along its parameters and conditions meaning that they too will be encoded in the key down the road.&lt;/p&gt;

&lt;h4 id='important_note'&gt;Important note&lt;/h4&gt;

&lt;p&gt;The action store doesn&amp;#8217;t take into account the content_type when caching, so if you use it for caching an action that provides more than one content_type, you will be in for some nasty surprise. (more on that in another blog post)&lt;/p&gt;

&lt;h2 id='the_gzipstore'&gt;The GzipStore&lt;/h2&gt;

&lt;p&gt;Compresses the content of the cache with gzip. Useful with a nginx module like &lt;a href='http://openhack.ru/nginx-patched/wiki/MemcachedGzip'&gt;MemcachedGzip&lt;/a&gt; that serves the gzip content directly from memcached (and decompresses it on the fly for clients that do not support gzip content)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;writable?&lt;/code&gt; always return true and when writing it keeps the key, parameters and conditions and just compresses the data.&lt;/p&gt;

&lt;h2 id='the_sha1store'&gt;The Sha1Store&lt;/h2&gt;

&lt;p&gt;It uses sha1 to digest the keys.&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; write(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; data &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; writable?(key, parameters, conditions)
        &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;stores&lt;/span&gt;.capture_first {|&lt;span class='Variables'&gt;c&lt;/span&gt;| c.write(digest(key, parameters), data, {}, conditions)}
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; digest(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;map&lt;/span&gt;[[key, parameters]] &lt;span class='Operators'&gt;||=&lt;/span&gt; Digest::SHA1.hexdigest(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;key&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;parameters&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;to_sha2&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;One thing to note is that it memoizes the result of the sha1 digest for the whole time your application is running.&lt;/p&gt;

&lt;h1 id='fundamental_stores'&gt;Fundamental Stores&lt;/h1&gt;

&lt;h2 id='filestore'&gt;Filestore&lt;/h2&gt;

&lt;p&gt;Used to store the cache on the file system.&lt;/p&gt;

&lt;h4 id='conditions_for_usage_'&gt;Conditions for usage (&lt;code&gt;writable?&lt;/code&gt;)&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='Comments'&gt;    &lt;span class='Comments'&gt;#&lt;/span&gt; File caching does not support expiration time.&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; writable?(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;case&lt;/span&gt; key
      &lt;span class='ControlStructures'&gt;when&lt;/span&gt; &lt;span class='Variables'&gt;String&lt;/span&gt;, &lt;span class='Variables'&gt;Numeric&lt;/span&gt;, &lt;span class='Variables'&gt;Symbol&lt;/span&gt;
        &lt;span class='Operators'&gt;!&lt;/span&gt;conditions.has_key?(&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;expire_in&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;else&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Works as long as the key is a string, numeric or symbol and when there is no :expire_in condition (memcached is better for that) So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doesn&amp;#8217;t work when called directly from the controller cache class method (it needs a strategy store like ActionStore or PageStore to generate the key for it and give it the data)&lt;/li&gt;

&lt;li&gt;Works with fetch_partial&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='memcachestore'&gt;MemcacheStore&lt;/h2&gt;

&lt;p&gt;Used to store cache in memcache&lt;/p&gt;

&lt;h4 id='conditions_for_usage_'&gt;Conditions for usage (&lt;code&gt;writable?&lt;/code&gt;)&lt;/h4&gt;

&lt;p&gt;Memcached store consideres all keys and parameters writable so &lt;code&gt;writable?&lt;/code&gt; is always true&lt;/p&gt;

&lt;h4 id='writing'&gt;Writing&lt;/h4&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='Comments'&gt;    &lt;span class='Comments'&gt;#&lt;/span&gt; Returns cache key calculated from base key&lt;/span&gt;
&lt;span class='Comments'&gt;    &lt;span class='Comments'&gt;#&lt;/span&gt; and SHA2 hex from parameters.&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; normalize(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      parameters.empty? &lt;span class='Operators'&gt;?&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;key&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; : &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;key&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;--&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;parameters&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;to_sha2&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;

&lt;span class='Comments'&gt;    &lt;span class='Comments'&gt;#&lt;/span&gt; Writes data to the cache using key, parameters and conditions.&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;def&lt;/span&gt; write(&lt;span class='Variables'&gt;key&lt;span class='Variables'&gt;,&lt;/span&gt; data &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; parameters &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;span class='Variables'&gt;,&lt;/span&gt; conditions &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;{&lt;/span&gt;&lt;span class='Variables'&gt;}&lt;/span&gt;&lt;/span&gt;)
      &lt;span class='ControlStructures'&gt;if&lt;/span&gt; writable?(key, parameters, conditions)
        &lt;span class='ControlStructures'&gt;begin&lt;/span&gt;
          &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;memcached&lt;/span&gt;.set(normalize(key, parameters), data, expire_time(conditions))
          &lt;span class='LanguageConstants'&gt;true&lt;/span&gt;
        &lt;span class='ControlStructures'&gt;rescue&lt;/span&gt;
          &lt;span class='LanguageConstants'&gt;nil&lt;/span&gt;
        &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
      &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The key is normalized by adding the parameters sha2 digest. When writing the expiration time is set to Time.now + :expire_in or 0&lt;/p&gt;

&lt;h1 id='summary'&gt;Summary&lt;/h1&gt;

&lt;h2 id='cache_methods'&gt;Cache Methods&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Context&lt;/th&gt;&lt;th&gt;Usage&lt;/th&gt;&lt;th&gt;Usable stores&lt;/th&gt;&lt;th&gt;Key type&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;cache&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller&lt;/td&gt;&lt;td style='text-align: left;'&gt;caches the result of the action&lt;/td&gt;&lt;td style='text-align: left;'&gt;PageStore, ActionStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;eager_cache&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller&lt;/td&gt;&lt;td style='text-align: left;'&gt;recaches the result of another action after the current action finishes using run later (great against dog piling)&lt;/td&gt;&lt;td style='text-align: left;'&gt;PageStore, ActionStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;fetch_partial&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;view&lt;/td&gt;&lt;td style='text-align: left;'&gt;fetches or caches the result of a partial&lt;/td&gt;&lt;td style='text-align: left;'&gt;GzipStore, Sha1Store, FileStore, MemcacheStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;string (&lt;code&gt;template_location&lt;/code&gt; returned by &lt;code&gt;_template_for&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;fetch_fragment&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller or view&lt;/td&gt;&lt;td style='text-align: left;'&gt;fetches or caches the result of a proc&lt;/td&gt;&lt;td style='text-align: left;'&gt;GzipStore, Sha1Store, FileStore, MemcacheStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;string either &lt;code&gt;:cache_key&lt;/code&gt; or the file and line the proc it&amp;#8217;s called with is declared&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id='strategic_stores'&gt;Strategic Stores&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Store&lt;/th&gt;&lt;th&gt;Key Type&lt;/th&gt;&lt;th&gt;writable? condition&lt;/th&gt;&lt;th&gt;Usage&lt;/th&gt;&lt;th&gt;Remarks&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;AdHocStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;any&lt;/td&gt;&lt;td style='text-align: left;'&gt;looks for its first writable? store&lt;/td&gt;&lt;td style='text-align: left;'&gt;Selects the most appropriate store&lt;/td&gt;&lt;td style='text-align: left;'&gt;order is important (should be from least likely to most likely writable)&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;PageStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller&lt;/td&gt;&lt;td style='text-align: left;'&gt;get request with no query string parameters (e.g. ?q=z) and no :if or :unless condition&lt;/td&gt;&lt;td style='text-align: left;'&gt;cache the page for webserver&lt;/td&gt;&lt;td style='text-align: left;'&gt;no support for reading (it&amp;#8217;s the work of the webserver)&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;ActionStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;controller&lt;/td&gt;&lt;td style='text-align: left;'&gt;only checks its stores&lt;/td&gt;&lt;td style='text-align: left;'&gt;cache actions that have parameters or conditions for caching&lt;/td&gt;&lt;td style='text-align: left;'&gt;doesn&amp;#8217;t encode &lt;code&gt;content_type&lt;/code&gt; in it&amp;#8217;s key&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;GzipStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;any&lt;/td&gt;&lt;td style='text-align: left;'&gt;always true&lt;/td&gt;&lt;td style='text-align: left;'&gt;compresses cache with gzip&lt;/td&gt;&lt;td style='text-align: left;'&gt;Useful with &lt;a href='http://openhack.ru/nginx-patched/wiki/MemcachedGzip'&gt;MemcachedGzip&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;Sha1Store&lt;/td&gt;&lt;td style='text-align: left;'&gt;string, numeric or symbol&lt;/td&gt;&lt;td style='text-align: left;'&gt;only checks its stores&lt;/td&gt;&lt;td style='text-align: left;'&gt;digest key + params with sha1&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id='fundamental_stores'&gt;Fundamental stores&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Store&lt;/th&gt;&lt;th&gt;Key Type&lt;/th&gt;&lt;th&gt;writable? condition&lt;/th&gt;&lt;th&gt;Usage&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;FileStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;string, numeric or symbol&lt;/td&gt;&lt;td style='text-align: left;'&gt;no &lt;code&gt;:expire_in condition&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Store the cache on the file system.&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;MemcacheStore&lt;/td&gt;&lt;td style='text-align: left;'&gt;any&lt;/td&gt;&lt;td style='text-align: left;'&gt;always true&lt;/td&gt;&lt;td style='text-align: left;'&gt;Store cache in memcache with expiration (&lt;code&gt;:expire_in condition&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=ADAcp6ra"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=ADAcp6ra" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=tzlfngpi"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=36yvHNi1"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=36yvHNi1" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/ardGRlGYw_M" height="1" width="1"/&gt;</description><pubDate>Tue, 09 Dec 2008 05:21:10 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/09/merb-cache-and-its-stores</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Merb-auth quick tip</title><link>http://gom-jabbar.org/articles/2008/12/08/merb-auth-quick-tip</link><description>&lt;h2 id='how_to_keep_things_in_the_session_object_even_after_logging_in'&gt;How to keep things in the session object even after logging in&lt;/h2&gt;

&lt;p&gt;If you look at the source code from the merb-auth-slice-password sessions controller you have the following before filters&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
 before &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;_maintain_auth_session_before&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;exclude&lt;/span&gt; =&amp;gt; [&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;destroy&lt;/span&gt;]  &lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; Need to hang onto the redirection during the session.abandon!&lt;/span&gt;
  before &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;_abandon_session&lt;/span&gt;,     &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;only&lt;/span&gt; =&amp;gt; [&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;update&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;destroy&lt;/span&gt;]
  before  &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;_maintain_auth_session_after&lt;/span&gt;,  &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;exclude&lt;/span&gt; =&amp;gt; [&lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;destroy&lt;/span&gt;]  &lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; Need to hang onto the redirection during the session.abandon!&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;and the associated code:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='Comments'&gt;  &lt;span class='Comments'&gt;#&lt;/span&gt; @private&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; _maintain_auth_session_before
    &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_maintain_auth_session&lt;/span&gt; &lt;span class='Operators'&gt;=&lt;/span&gt; {}
    Merb::Authentication.maintain_session_keys.each &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;k&lt;/span&gt;|
      &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_maintain_auth_session&lt;/span&gt;[k] &lt;span class='Operators'&gt;=&lt;/span&gt; session[k]
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  
&lt;span class='Comments'&gt;  &lt;span class='Comments'&gt;#&lt;/span&gt; @private&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; _maintain_auth_session_after
    &lt;span class='Variables'&gt;&lt;span class='Variables'&gt;@&lt;/span&gt;_maintain_auth_session&lt;/span&gt;.each &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;k&lt;/span&gt;,&lt;span class='Variables'&gt;v&lt;/span&gt;|
      session[k] &lt;span class='Operators'&gt;=&lt;/span&gt; v
    &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
  
&lt;span class='Comments'&gt;  &lt;span class='Comments'&gt;#&lt;/span&gt; @private&lt;/span&gt;
  &lt;span class='ControlStructures'&gt;def&lt;/span&gt; _abandon_session
    session.abandon!
  &lt;span class='ControlStructures'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;So if you want to keep some elements from the session accross login you just need to add the keys to Merb::Authentication.maintain_session_keys&lt;/p&gt;

&lt;p&gt;Like this: (I put it in merb/merb-auth/setup.rb)&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
	Merb::Authentication.maintain_session_keys &lt;span class='Operators'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;lang&lt;/span&gt; &lt;span class='Operators'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;guest&lt;/span&gt;
&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=yQWbl1zT"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=yQWbl1zT" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=cbzA9zEn"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=t9rbJD19"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=t9rbJD19" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/ggpeAjlJarc" height="1" width="1"/&gt;</description><pubDate>Mon, 08 Dec 2008 12:43:23 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/08/merb-auth-quick-tip</guid><dc:creator>Guillaume Maury</dc:creator></item><item><title>Please use bcrypt to store your passwords</title><link>http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords</link><description>&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: If you want to use bcrypt with merb-auth, I have made a patch available at &lt;a href='http://merb.lighthouseapp.com/projects/7433/tickets/1113-bcrypt-mixin-for-merb-auth-more'&gt;http://merb.lighthouseapp.com/projects/7433/tickets/1113-bcrypt-mixin-for-merb-auth-more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently most people on merb use sha1 hashes and salt the passwords with a nounce to store it. It&amp;#8217;s a good practice, it protects you from the reddit embarrassment where a database full of plaintext passwords got leaked because, apart from brute-forcing, there is no way to reverse the hash to find the password. And by salting your hash with a nounce you protect yourself against from pre-generated rainbow tables. So all is good, right?&lt;/p&gt;

&lt;p&gt;Well mostly, but why use md5 or sha1? They are made to be fast&amp;#8230; Cryptographic hash functions are fast by design, as the buiding blocks of all cryptographic systems, they need to be. And of course, since they are used repeatidily, it makes sense to optimize hardware for it&amp;#8230; So it&amp;#8217;s possible to use something like nsa@home &lt;a href='http://nsa.unaligned.org/'&gt;http://nsa.unaligned.org/&lt;/a&gt; made of FPGAs that can search the full 8-character keyspace (from a 64-character set) in about a day for 800 hashes concurrently&amp;#8230;.&lt;/p&gt;

&lt;p&gt;To attack a password scheme, you would normally use an incremental cracker (a rainbow table cracker is not much use if you the passwords are salted with a nounce) and those cracker rely on the speed of the hashing operation, the faster it is to hash your password, the more combinations you can try and the weaker your password scheme is.&lt;/p&gt;

&lt;p&gt;So what can you use instead? You can use BCrypt an adaptive hashing scheme&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It&amp;#8217;s made to be computationally expensive by using blowfish block cypher that is slow to set up.&lt;/li&gt;

&lt;li&gt;You can configure the cost of the hashing function to make it slower&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Currently the cost is set to 10 by default but you can change it and make it higher as hardwares speed go up&amp;#8230; All the password using the old cost will continue to work (bcrypt-ruby stores the cost along with the password) and new passwords will have a higher cost.&lt;/p&gt;

&lt;p&gt;Some quick benchmark:&lt;/p&gt;
&lt;pre class='pastels_on_dark'&gt;
&lt;span class='Keywords'&gt;require&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;sha1&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class='Keywords'&gt;require&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;bcrypt&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class='Keywords'&gt;require&lt;/span&gt; &lt;span class='Strings'&gt;&lt;span class='Strings'&gt;'&lt;/span&gt;md5&lt;span class='Strings'&gt;'&lt;/span&gt;&lt;/span&gt;

Benchmark.bm(&lt;span class='Numbers'&gt;20&lt;/span&gt;) &lt;span class='ControlStructures'&gt;do &lt;/span&gt;|&lt;span class='Variables'&gt;x&lt;/span&gt;|
  x.report(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;BCrypt (cost = 12):&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) { &lt;span class='Numbers'&gt;500&lt;/span&gt;.times { &lt;span class='Variables'&gt;BCrypt&lt;/span&gt;::Password.create(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;cost&lt;/span&gt; =&amp;gt; &lt;span class='Numbers'&gt;12&lt;/span&gt;) } }
  x.report(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;BCrypt (cost = 10):&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) { &lt;span class='Numbers'&gt;500&lt;/span&gt;.times { &lt;span class='Variables'&gt;BCrypt&lt;/span&gt;::Password.create(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;cost&lt;/span&gt; =&amp;gt; &lt;span class='Numbers'&gt;10&lt;/span&gt;) } }
  x.report(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;BCrypt (cost = 5):&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) { &lt;span class='Numbers'&gt;500&lt;/span&gt;.times { &lt;span class='Variables'&gt;BCrypt&lt;/span&gt;::Password.create(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class='Constants'&gt;&lt;span class='Constants'&gt;:&lt;/span&gt;cost&lt;/span&gt; =&amp;gt; &lt;span class='Numbers'&gt;2&lt;/span&gt;) } }
  x.report(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;md5:&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)  { &lt;span class='Numbers'&gt;500&lt;/span&gt;.times { salt &lt;span class='Operators'&gt;=&lt;/span&gt; &lt;span class='Variables'&gt;MD5&lt;/span&gt;.hexdigest(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;--&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;&lt;span class='Strings'&gt;Time&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;now&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;to_s&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;--username--&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); &lt;span class='Variables'&gt;MD5&lt;/span&gt;.hexdigest(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;mypass-&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;salt&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) } }
  x.report(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;Sha1:&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) { &lt;span class='Numbers'&gt;500&lt;/span&gt;.times { salt &lt;span class='Operators'&gt;=&lt;/span&gt; Digest::SHA1.hexdigest(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;--&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;&lt;span class='Strings'&gt;Time&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;now&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;.&lt;/span&gt;&lt;span class='Strings'&gt;to_s&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;--username--&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); Digest::SHA1.hexdigest(&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;mypass-&lt;span class='Strings'&gt;&lt;span class='Strings'&gt;#{&lt;/span&gt;salt&lt;span class='Strings'&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class='Strings'&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) } }
&lt;span class='ControlStructures'&gt;end&lt;/span&gt;

&lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt;                           user     system      total        real&lt;/span&gt;
&lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; BCrypt (cost = 12): 250.140000   5.130000 255.270000 (276.009547)&lt;/span&gt;
&lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; BCrypt (cost = 10):  62.680000   1.230000  63.910000 ( 69.320089)&lt;/span&gt;
&lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; BCrypt (cost = 5):    1.090000   0.020000   1.110000 (  1.185847)&lt;/span&gt;
&lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; md5:                  0.010000   0.000000   0.010000 (  0.008147)&lt;/span&gt;
&lt;span class='Comments'&gt;&lt;span class='Comments'&gt;#&lt;/span&gt; Sha1:                 0.000000   0.000000   0.000000 (  0.008906)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The point is that you don&amp;#8217;t care about the time needed to hash a single password in your system it&amp;#8217;s not a bottleneck (0.12 seconds on my mac) but attacker will&amp;#8230;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/giom?a=CKMlvYzz"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=CKMlvYzz" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=P0HqRjqg"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/giom?a=IVFQToKU"&gt;&lt;img src="http://feeds.feedburner.com/~f/giom?i=IVFQToKU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/giom/~4/6Gq-_DStpg0" height="1" width="1"/&gt;</description><pubDate>Tue, 02 Dec 2008 23:09:01 GMT</pubDate><guid>http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords</guid><dc:creator>Guillaume Maury</dc:creator></item></channel></rss>

