<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Jordi Romero</title>
  <updated>2011-12-01T12:00:00-08:00</updated>
  <generator uri="http://jrom.net">jrom.net</generator>
  <id>tag:jrom.net,2010:/</id>
  <link href="http://jrom.net/articles.xml" rel="self"/>
  <link href="http://jrom.net" rel="alternate"/>
  <author>
    <name>Jordi Romero</name>
    <uri>http://jrom.net</uri>
  </author>
  <entry>
    <title>API design and more</title>
    <link type="text/html" href="http://jrom.net/api-design-and-more" rel="alternate"/>
    <id>tag:jrom.net,2011-12-01:/api-design-and-more</id>
    <content type="html">&lt;p&gt;This is the description (and slides) from the talk I gave at the &lt;a href='http://toster.ru/'&gt;toster.ru&lt;/a&gt; conference in Moscow.&lt;/p&gt;

&lt;p&gt;The main point of the talk is to go through every major design decision around API design, so both API producers and consumers know what to offer or expect from a well designed &lt;strong&gt;REST API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;REST APIs are essential in any modern web application. It&amp;#8217;s currently a trend not to build &lt;em&gt;Web Apps&lt;/em&gt; but &lt;em&gt;Platforms&lt;/em&gt;. A good REST API is the core of the platform, where web apps, mobile apps, 3rd party integrations, etc. can just use as its brain.&lt;/p&gt;

&lt;p&gt;Some of the concepts the talk goes around are: HTTP, REST, URI, metadata, representations, security, versioning, pagination. These are all relevant aspects of a good REST API design. After that, some tips about &lt;strong&gt;implementation&lt;/strong&gt; and &lt;strong&gt;deployment&lt;/strong&gt; are thrown to the mix. Finally, &lt;strong&gt;scaling&lt;/strong&gt; is mentioned as a key challenge a successful API will find. Horizontal scaling, HTTP cache, application cache, database replication and asynchrony are mentioned as possible methods to help the scaling of an API, although the design will still carry most of the responsability to decide if an API can scale easily or not.&lt;/p&gt;

&lt;p&gt;&lt;a href='https://speakerd.s3.amazonaws.com/presentations/4ed88ddb013097005000379b/api-for-the-mobile-era.pdf'&gt;Download the PDF&lt;/a&gt; or see it embedded here:&lt;/p&gt;
&lt;script src='http://speakerdeck.com/embed/4ed88ddb013097005000379b.js' /&gt;</content>
    <published>2011-12-01T12:00:00-08:00</published>
    <updated>2011-12-01T12:00:00-08:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Teambox: Starting and learning</title>
    <link type="text/html" href="http://jrom.net/starting-and-learning" rel="alternate"/>
    <id>tag:jrom.net,2011-11-17:/starting-and-learning</id>
    <content type="html">&lt;p&gt;Slides from my talk at the &lt;a href='http://bcndevcon.org/'&gt;Barcelona Developer Conference 2011&lt;/a&gt;.&lt;/p&gt;
&lt;script src='http://speakerdeck.com/embed/4ec50458e2f5020054007f5a.js' /&gt;</content>
    <published>2011-11-17T14:00:00-08:00</published>
    <updated>2011-11-17T14:00:00-08:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Stop being Paranoid, be Immortal</title>
    <link type="text/html" href="http://jrom.net/stop-being-paranoid-be-immortal" rel="alternate"/>
    <id>tag:jrom.net,2011-01-16:/stop-being-paranoid-be-immortal</id>
    <content type="html">&lt;p&gt;A while ago, &lt;a href='https://github.com/saimonmoore'&gt;Saimon&lt;/a&gt; and I started upgrading &lt;a href='http://teambox.com'&gt;Teambox&lt;/a&gt; to Rails 3. Once we got a bootable application (more on that in another post) the first big problem we faced was &lt;code&gt;acts_as_paranoid&lt;/code&gt;. Its internals are a mess, so there was no chance we could just &lt;em&gt;fix&lt;/em&gt; that for Rails 3. We decided we would just write a brand new gem that shared the API as much as possible.&lt;/p&gt;

&lt;p&gt;The main goals were: implement almost the whole API from acts_as_paranoid (this way the impact of replacing it in Teambox would be minimal) and make it as small and lightweight as possible. We are true BDD believers, so we started writing a &lt;a href='https://github.com/teambox/immortal/blob/29ffd7/spec/immortal_spec.rb'&gt;spec&lt;/a&gt; for what we needed. After that, writing the &lt;a href='https://github.com/teambox/immortal/blob/29ffd7/lib/immortal.rb'&gt;code&lt;/a&gt; was quite easy.&lt;/p&gt;

&lt;p&gt;In our way, we changed some assumptions from acts_as_paranoid, such as the need of storing &lt;strong&gt;when&lt;/strong&gt; a row was deleted. Because of that, we no longer needed a &lt;code&gt;deleted_at&lt;/code&gt; field but a boolean &lt;code&gt;deleted&lt;/code&gt; field. This change demands a migration:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class MigrateParanoidFields &amp;lt; ActiveRecord::Migration
  def self.up
    add_column :users, :deleted, :boolean
    add_index :users, [:deleted]
    User.update_all [&amp;quot;deleted = ?&amp;quot;, true], &amp;quot;deleted_at IS NOT NULL&amp;quot;
    remove_column :users, :deleted_at
  end

  def self.down
    add_column :users, :deleted_at, :datetime
    add_index :users, [:deleted_at]
    User.update_all [&amp;quot;deleted_at = ?&amp;quot;, Time.now], [&amp;quot;deleted = ?&amp;quot;, true]
    remove_column :users, :deleted
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While doing all this, at some point I regretted changing the &lt;code&gt;deleted&lt;/code&gt; field to a boolean, because it looks like every relational database out there decides to implement (or not) their own boolean data type. This is where &lt;a href='https://github.com/rails/arel'&gt;Arel&lt;/a&gt; comes handy, because you can just do something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;default_scope where(arel_table[:deleted].eq(nil).or(arel_table[:deleted].eq(false)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Although there has been &lt;a href='http://blog.semanticart.com/2009/10/13/killing-is-paranoid.html'&gt;discussions&lt;/a&gt; about the convenience of using &lt;code&gt;default_scope&lt;/code&gt; for anything other than &lt;code&gt;order&lt;/code&gt;, it just feels right to do it in this use case.&lt;/p&gt;

&lt;p&gt;To sum up: the code is available at &lt;a href='https://github.com/teambox/immortal'&gt;github&lt;/a&gt; or just as a &lt;a href='https://rubygems.org/gems/immortal'&gt;Ruby Gem&lt;/a&gt;. Please feel free to contribute, &lt;a href='https://github.com/unixcharles'&gt;Charles&lt;/a&gt; already &lt;a href='https://github.com/teambox/immortal/commit/3bc92da646009425a45e205d0cc60e8eef205ea1'&gt;did it&lt;/a&gt;!&lt;/p&gt;</content>
    <published>2011-01-16T13:00:00-08:00</published>
    <updated>2011-01-16T13:00:00-08:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>I did it again!</title>
    <link type="text/html" href="http://jrom.net/i-did-it-again" rel="alternate"/>
    <id>tag:jrom.net,2011-01-10:/i-did-it-again</id>
    <content type="html">&lt;p&gt;I &lt;a href='/i-like-coding-blogs'&gt;said it once&lt;/a&gt; already, but I&amp;#8217;m going to talk about the same thing today. I enjoy rewriting or reimplementing blog engines. Most definitely more than writing blog posts.&lt;/p&gt;

&lt;p&gt;The last time I did that, I kept the design and went from a &lt;a href='https://github.com/jrom/jromrb'&gt;sinatra app with database backend&lt;/a&gt; to a &lt;a href='https://github.com/jrom/jrom.net'&gt;git-backed engine&lt;/a&gt; (a fork of &lt;a href='http://effectif.com/nesta'&gt;Nesta&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This time, i kept absolutely everything (design, html, feed, sitemap, about pages, etc.) but went to the static site generator &lt;a href='https://github.com/mojombo/jekyll'&gt;Jekyll&lt;/a&gt;. The goal was to make this change transparent to the (possible) readers, search engines and feed subscribers would never notice the change, except for this post. In the last &lt;em&gt;migration&lt;/em&gt; I moved all the blog posts to Markdown files, this was very nice, because I love formatting text using that markup language, and I still use it with Jekyll. The worst part were the haml and sass files. There&amp;#8217;s no support for haml or sass on Github Pages (the generator I&amp;#8217;m using to host this blog now), so I had to go back to plain CSS and HTML. This made me sad, but I definitely wanted everything in the same place and without using weird deployment strategies. Just git push for both posts and layout modifications. Github pages were the answer, so the move back made sense to me.&lt;/p&gt;

&lt;p&gt;Other than that, I just had to replace some haml/erb/builder files with plain html/xml using &lt;a href='http://www.liquidmarkup.org/'&gt;Liquid&lt;/a&gt; and make sure everything was smooth again.&lt;/p&gt;

&lt;p&gt;Thanks to the awesome &lt;a href='http://pages.github.com/'&gt;&lt;strong&gt;Github pages&lt;/strong&gt;&lt;/a&gt; service, all I had to do is push to &lt;a href='https://github.com/jrom/jrom.github.com'&gt;github.com/jrom/jrom.github.com&lt;/a&gt; and wait a couple of minutes.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;</content>
    <published>2011-01-10T01:00:00-08:00</published>
    <updated>2011-01-10T01:00:00-08:00</updated>
    
  </entry>
  <entry>
    <title>Super simple authentication in Rails</title>
    <link type="text/html" href="http://jrom.net/super-simple-authentication-in-rails" rel="alternate"/>
    <id>tag:jrom.net,2010-05-07:/super-simple-authentication-in-rails</id>
    <content type="html">&lt;p&gt;Here comes another short but (hopefully) useful Rails trick. In my client applications I often need to do some protected section to do backoffice stuff or similar. Sometimes I need a fully featured &lt;strong&gt;authentication system&lt;/strong&gt;, then usually use &lt;a href='http://github.com/binarylogic/authlogic'&gt;Authlogic&lt;/a&gt; (although I&amp;#8217;m willing to try &lt;a href='http://github.com/plataformatec/devise'&gt;Devise&lt;/a&gt;). Some other times you just need to hide a page to the public, and one password just works. And like everything in Rails, there&amp;#8217;s a quick way of doing that.&lt;/p&gt;

&lt;p&gt;All you need is some controller code to protect the private pages and some code to check the credentials. The easier way is not even creating any HTML code for that and take advantage of the HTTP Authentication. Here&amp;#8217;s what I do in &lt;code&gt;app/controllers/application_controller.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;helper_method :logged_in?

def logged_in?
  session[:login]
end

private
def authenticate
  login = authenticate_or_request_with_http_basic do |username, password|
    username == &amp;quot;username&amp;quot; &amp;amp;&amp;amp; password == &amp;quot;password&amp;quot;
  end
  session[:login] = login
end

def do_logout
  session[:login] = nil
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now all it takes to force the user to authenticate for viewing some action, you just need to add a &lt;code&gt;before_filter&lt;/code&gt; in that controller. It may look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class NewsController &amp;lt; ApplicationController
  before_filter :authenticate, :except =&amp;gt; [:index, :show]
  # ...
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we are allowing public access to list and show a &lt;em&gt;New&lt;/em&gt; but we are restricting all other actions (for example, creating, editing or destroying &lt;em&gt;News&lt;/em&gt;) unless authenticated, but that&amp;#8217;s getting &lt;em&gt;offtopic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As a small extra, there&amp;#8217;s a helper method useful to show or hide special menus or something in the views, just put any &lt;em&gt;private&lt;/em&gt; html inside an &lt;code&gt;if logged_in? ... end&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That solution was really &lt;em&gt;quick&lt;/em&gt;, but not very elegant. We don&amp;#8217;t want our credentials hardcoded into a controller, and sure we don&amp;#8217;t want our password in clear text! One better solution would be to use a &lt;a href='/config-file-in-rails-apps'&gt;config file&lt;/a&gt; and hash the password, replacing the comparison line with this one:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;username == APP_CONFIG[&amp;#39;username&amp;#39;] &amp;amp;&amp;amp; Digest::SHA1.hexdigest(password) == APP_CONFIG[&amp;#39;password&amp;#39;]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And of course storing this two variables in our config YAML file. To create the hashed version of the password for the config file the easiest way is by using the Rails console or just &lt;code&gt;irb&lt;/code&gt;, and use the &lt;code&gt;hexdigest&lt;/code&gt; method shown here. This will provide a quick but nice solution to our private sections.&lt;/p&gt;</content>
    <published>2010-05-07T18:00:00-07:00</published>
    <updated>2010-05-07T18:00:00-07:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>Gmail in Mutt</title>
    <link type="text/html" href="http://jrom.net/gmail-in-mutt" rel="alternate"/>
    <id>tag:jrom.net,2010-04-30:/gmail-in-mutt</id>
    <content type="html">&lt;p&gt;&lt;img src='/files/gmail-in-mutt/mutts.png' alt='Screenshot of the Mutt mail client' /&gt; &lt;strong&gt;Mutt&lt;/strong&gt; is an open-source (&lt;a href='http://www.gnu.org/licenses/gpl.html'&gt;GPL&lt;/a&gt;) text-based mail client for Unix. It may not be the best client if you receive a lot of messages formatted with HTML (most newsletters or &lt;em&gt;good&lt;/em&gt; spam are), but it&amp;#8217;s a nice program to know, because some day you may feel more hacker and want to use it.&lt;/p&gt;

&lt;p&gt;To use Mutt, you must first install it. But that&amp;#8217;s too easy: it&amp;#8217;s on every &lt;em&gt;&lt;acronym title='FreeBSD&amp;apos;s ports, Debian&amp;apos;s dpkg, OS X&amp;apos;s macports, homebrew, etc.'&gt;package management system&lt;/acronym&gt;&lt;/em&gt; after that weird name: &lt;strong&gt;mutt&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before touching &lt;strong&gt;Mutt&lt;/strong&gt;, you must enable Gmail&amp;#8217;s IMAP for your account, going to &lt;strong&gt;Settings&lt;/strong&gt; &amp;#8594; &lt;strong&gt;Forwarding and POP/IMAP&lt;/strong&gt; &amp;#8594; &lt;strong&gt;Enable IMAP&lt;/strong&gt;. &lt;a href='/files/gmail-in-mutt/gmail-imaps.png'&gt;Like this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that comes the only tricky part: configuring Mutt to check your Gmail&amp;#8217;s IMAP Inbox and send emails through Google&amp;#8217;s SMTP server. And I already did the research on what&amp;#8217;s needed to this. I&amp;#8217;m using &lt;a href='http://www.google.com/apps/'&gt;Google Apps&lt;/a&gt; for my personal domain, and it works exactly like a regular &lt;code&gt;@gmail.com&lt;/code&gt; account, with the only difference of the username format. (Google Apps is absolutely a &lt;em&gt;must-have&lt;/em&gt; for your domain unless you have some bigger solution).&lt;/p&gt;

&lt;p&gt;You need to populate your &lt;code&gt;~/.muttrc&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Me
set from = &amp;quot;you@gmail_or_your_domain.com&amp;quot;
set realname = &amp;quot;Jordi Romero&amp;quot;

# My credentials
set smtp_url = &amp;quot;smtp://you@gmail_or_your_domain.com@smtp.gmail.com:587/&amp;quot;
set smtp_pass = &amp;quot;password&amp;quot;
set imap_user = &amp;quot;you@gmail_or_your_domain.com&amp;quot;
set imap_pass = &amp;quot;password&amp;quot;

# My mailboxes
set folder = &amp;quot;imaps://imap.gmail.com:993&amp;quot;
set spoolfile = &amp;quot;+INBOX&amp;quot;
set postponed = &amp;quot;+[Gmail]/Drafts&amp;quot;

# Where to put the stuff
set header_cache = &amp;quot;~/.mutt/cache/headers&amp;quot;
set message_cachedir = &amp;quot;~/.mutt/cache/bodies&amp;quot;
set certificate_file = &amp;quot;~/.mutt/certificates&amp;quot;

# Etc
set mail_check = 30
set move = no
set imap_keepalive = 900
set sort = threads
set editor = &amp;quot;vim&amp;quot;

# GnuPG bootstrap
# source ~/.mutt/gpg.rc&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course you&amp;#8217;ll want to &lt;code&gt;chmod 700 ~/.muttrc&lt;/code&gt; if you put that kind of sensitive data, or just don&amp;#8217;t specify your passwords and will be prompted every time (for example in a non private environment). And you will also need to &lt;code&gt;mkdir -p ~/.mutt/cache&lt;/code&gt; before firing mutt.&lt;/p&gt;

&lt;h3 id='using_mutt'&gt;Using Mutt&lt;/h3&gt;

&lt;p&gt;Now you can start it by typing &lt;code&gt;mutt&lt;/code&gt; in a terminal. Read the &lt;a href='http://www.mutt.org/doc/manual/manual-2.html'&gt;Documentation&lt;/a&gt; on how to move and use Mutt. The main concepts are similar to vim&amp;#8217;s navigation shortcuts.&lt;/p&gt;

&lt;h3 id='encryption_with_gnupg'&gt;Encryption with GnuPG&lt;/h3&gt;

&lt;p&gt;One of the nice things about Mutt is that it has &lt;strong&gt;encryption&lt;/strong&gt;/&lt;strong&gt;signing&lt;/strong&gt; support out of the box. You just need to setup your keys in your environment and it will do the rest. If you already have your key in the ~/.gnupg/ directory, skip to the next point.&lt;/p&gt;

&lt;p&gt;As before, you first need to install &lt;strong&gt;gnupg&lt;/strong&gt; with your package management system. After that, you will need to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Generate your key
# You can use the default answers
# Choose a strong passphrase
gpg --gen-key

# Generate your Public key
gpg --armor --output pubkey.txt --export &amp;#39;name&amp;#39;

# Register your public key in a public server
gpg --send-keys --keyserver hkp://subkeys.pgp.net&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And you are done. You can share your &lt;code&gt;pubkey.txt&lt;/code&gt; with everybody and everybody will be able to send you encrypted mails or check your signed messages.&lt;/p&gt;

&lt;p&gt;Besides that, to setup correctly the environment for Mutt, you will have to uncomment the last line of the &lt;code&gt;~/.muttrc&lt;/code&gt; and copy the &lt;a href='/files/gmail-in-mutt/gpg.rc'&gt;gpg.rc&lt;/a&gt; file to &lt;code&gt;~/.mutt/gpg.rc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can fire &lt;strong&gt;Mutt&lt;/strong&gt; again and encrypt or sign a message by pressing the &lt;strong&gt;p&lt;/strong&gt; key just before sending (&lt;strong&gt;y&lt;/strong&gt;). Decryption or signature verification is done behind the scenes.&lt;/p&gt;

&lt;h3 id='feedback_highly_appreciated'&gt;Feedback highly appreciated&lt;/h3&gt;

&lt;p&gt;I hope some of you will actually use Mutt and give back to me some tips! Until the comments are on, please use the &lt;a href='/contact'&gt;contact page&lt;/a&gt;.&lt;/p&gt;</content>
    <published>2010-04-30T18:00:00-07:00</published>
    <updated>2010-04-30T18:00:00-07:00</updated>
    
  </entry>
  <entry>
    <title>Config file in Rails apps</title>
    <link type="text/html" href="http://jrom.net/config-file-in-rails-apps" rel="alternate"/>
    <id>tag:jrom.net,2010-04-28:/config-file-in-rails-apps</id>
    <content type="html">&lt;p&gt;How many times do you find yourself hardcoding something that you now you&amp;#8217;ll have to refactor and extract into a config file? But you don&amp;#8217;t, because you don&amp;#8217;t have that config file, and you don&amp;#8217;t want to loose 10 minutes thinking (or the XXI&amp;#8217;s century equivalent, googling) a solution. If you are nodding and feeling guilty, continue reading.&lt;/p&gt;

&lt;p&gt;In an existent Rails application, just type&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rake rails:template LOCATION=http://github.com/jrom/rails-app.yml/raw/master/rails-app.yml.rb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or if you are about to create the app, extend the rails command like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails &amp;lt;app&amp;gt; -m http://github.com/jrom/rails-app.yml/raw/master/rails-app.yml.rb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That wasn&amp;#8217;t hard, was it? The code that just ran is &lt;strong&gt;so&lt;/strong&gt; simple that you can go &lt;a href='http://github.com/jrom/rails-app.yml/blob/master/rails-app.yml.rb'&gt;check it&lt;/a&gt;. After asking you the name of that config (or assuming the default: &lt;em&gt;app&lt;/em&gt;) it will create the &lt;strong&gt;YAML&lt;/strong&gt; file under the &lt;code&gt;config&lt;/code&gt; directory and create an initializer to load its content when the application starts. The config comes with a demo variable, defined in the three typical Rails environments: &lt;em&gt;production&lt;/em&gt;, &lt;em&gt;development&lt;/em&gt; and &lt;em&gt;test&lt;/em&gt;. You can use &lt;code&gt;APP_CONFIG['variable']&lt;/code&gt; (if the config name was app) anywhere and it will return the value for the current environment and that variable.&lt;/p&gt;

&lt;p&gt;Enjoy it and use the &lt;a href='http://github.com/jrom/rails-app.yml/issues'&gt;issues&lt;/a&gt; section in Github for any comment about the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus plus&lt;/strong&gt;: it&amp;#8217;s Rails 3 compatible!&lt;/p&gt;</content>
    <published>2010-04-28T23:00:00-07:00</published>
    <updated>2010-04-28T23:00:00-07:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>Page caching with Sinatra and nginx</title>
    <link type="text/html" href="http://jrom.net/page-caching-with-sinatra-and-nginx" rel="alternate"/>
    <id>tag:jrom.net,2010-04-28:/page-caching-with-sinatra-and-nginx</id>
    <content type="html">&lt;p&gt;&lt;img src='/files/page-caching-with-sinatra-and-nginx/sinatra.gif' alt='Sinatra' /&gt; I&amp;#8217;ve built some small websites with Sinatra lately (this blog itself). And in exactly all the cases I needed page caching, because the content would change once a month, a week, or a day. Page caching is &lt;strong&gt;easy&lt;/strong&gt;, but sometimes you just need some tip. Let&amp;#8217;s fix that by giving some simple and direct instructions in order to enable page caching and serving it from nginx:&lt;/p&gt;

&lt;p&gt;First of all, we need &lt;a href='http://github.com/kematzy/sinatra-cache' title='sinatra-cache on Github'&gt;Sinatra::Cache&lt;/a&gt;, the Sinatra extension that will make our life much nicer. You can either &lt;code&gt;gem install sinatra-cache&lt;/code&gt; or add &lt;code&gt;gem &quot;sinatra-cache&quot;, &quot;0.3.2&quot;&lt;/code&gt; to your Gemfile.&lt;/p&gt;

&lt;p&gt;After that, you will have to require and activate the extension in a &lt;em&gt;configure&lt;/em&gt; block:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &amp;#39;sinatra/cache&amp;#39;

module Jrom
  class Application &amp;lt; Sinatra::Base
    configure do
      register(Sinatra::Cache)
      set :root, File.dirname(__FILE__)
      set :cache_enabled, true
      set :cache_output_dir, Proc.new { File.join(root, &amp;#39;public&amp;#39;, &amp;#39;cache&amp;#39;) }
    end

    get &amp;#39;/&amp;#39; do
      &amp;quot;Hi there&amp;quot;
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, first we &lt;em&gt;register&lt;/em&gt; it, and then set a couple of config options. Actually, I wasn&amp;#8217;t able to get it to work in a &lt;em&gt;classic style&lt;/em&gt; app (when you just start coding &lt;em&gt;get&lt;/em&gt;&amp;#8217;s and &lt;em&gt;post&lt;/em&gt;&amp;#8217;s to the Ruby file, opposed to creating a subclass of &lt;em&gt;Sinatra::Base&lt;/em&gt;), and that&amp;#8217;s why I&amp;#8217;m using the &lt;em&gt;subclass style&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If this is the first time you see a Sinatra application using the &lt;em&gt;Sinatra::Base&lt;/em&gt; thing, just remember to have a &lt;code&gt;config.ru&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &amp;#39;app&amp;#39;
run Jrom::Application&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;#8217;s continue, now we have our Sinatra app performing caching (by default it only does in production environment, check the &lt;em&gt;cache_environment&lt;/em&gt; setting to change that if needed). A lot of people would stop here and go have some beers happy with an app that will be creating a cached page in &lt;strong&gt;every request&lt;/strong&gt;, doing actually &lt;strong&gt;more work&lt;/strong&gt; instead of less&amp;#8230; That&amp;#8217;s lame, but a lot of people does it.&lt;/p&gt;

&lt;p&gt;&lt;img src='/files/page-caching-with-sinatra-and-nginx/nginx.gif' alt='nginx' /&gt; The next but very important step is telling the web server (aka &lt;strong&gt;nginx&lt;/strong&gt;) to serve the cached page if there is some. The following code must be added in the &lt;code&gt;server { ... }&lt;/code&gt; block of the nginx config:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if (-f $request_filename)
{
  break;
}

if (-f $document_root/cache$request_filename)
{
  rewrite (.*) /cache$1 break;
  break;
}

if (-f $document_root/cache$request_uri.html)
{
  rewrite (.*) /cache$1.html break;
  break;
}

if (-f $document_root/cache$request_uri/index.html)
{
  rewrite (.*) /cache$1/index.html break;
  break;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code is derived from the one published by Josh Susser on this &lt;a href='http://blog.hasmanythrough.com/2008/1/30/segregated-page-cache-storage'&gt;blog post&lt;/a&gt;. His code &lt;em&gt;as is&lt;/em&gt; didn&amp;#8217;t work for me, if you know why, please tell me.&lt;/p&gt;

&lt;p&gt;Now our app is caching and enjoying the cached files nicely. But two small tweaks can still be done:&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;&amp;lt;%= cache_timestamp %&amp;gt;&lt;/code&gt; in your layout to print a comment with the timestamp when the page was cached, and add this &lt;strong&gt;Capistrano&lt;/strong&gt; tasks to create the cache directory, link it to shared and flush the cached files when deploying:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;after &amp;quot;deploy:setup&amp;quot;, &amp;quot;create_page_cache&amp;quot;
desc &amp;quot;Creates the cache dir&amp;quot;
task :create_page_cache, :roles =&amp;gt; :app do
  run &amp;quot;umask 02 &amp;amp;&amp;amp; mkdir -p #{shared_path}/cache&amp;quot;
end

after &amp;quot;deploy:update_code&amp;quot;,&amp;quot;symlink_shared_dirs&amp;quot;
desc &amp;quot;Links the public/cache with the shared/cache&amp;quot;
task :symlink_shared_dirs, :roles =&amp;gt; :app do
  run &amp;quot;cd #{release_path} &amp;amp;&amp;amp; ln -nfs {shared_path}/cache #{release_path}/public/cache&amp;quot;
end

set :flush_cache, true

task :keep_page_cache do
  set :flush_cache, false
end

after &amp;quot;deploy:cleanup&amp;quot;, &amp;quot;flush_page_cache&amp;quot;
desc &amp;quot;Empties the page cache&amp;quot;
task :flush_page_cache, :roles =&amp;gt; :app do
  if flush_cache
    run &amp;quot;rm -rf #{shared_path}/cache/*&amp;quot;
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I think that&amp;#8217;s enough to get a healthy Sinatra application performing page caching and flushing when deploying. You can also use the &lt;code&gt;cache_expire('/path')&lt;/code&gt; to expire pages on some actions (e.g.. when an article is saved), but that&amp;#8217;s out of this post&amp;#8217;s subject, just read the doc of the extension.&lt;/p&gt;

&lt;p&gt;I hope that was useful to somebody, and I encourage you to cache every possible page in your web applications. The performance boost will be incredible.&lt;/p&gt;</content>
    <published>2010-04-28T01:00:00-07:00</published>
    <updated>2010-04-28T01:00:00-07:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>I like coding blogs</title>
    <link type="text/html" href="http://jrom.net/i-like-coding-blogs" rel="alternate"/>
    <id>tag:jrom.net,2010-04-27:/i-like-coding-blogs</id>
    <content type="html">&lt;p&gt;As I &lt;a href='/hi-again'&gt;just mentioned&lt;/a&gt;, I&amp;#8217;ve been in a passive-aggressive relationship with my blogger alter ego. There are many reasons to that, but one is more interesting to me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I enjoy more writing blog engines than writing blog posts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&amp;#8217;ve been using &lt;em&gt;Wordpress&lt;/em&gt; most of the time, for which I developed some themes (most of them lost, but I just keep the &lt;a href='http://github.com/jrom/jrom09'&gt;last&lt;/a&gt; &lt;a href='http://github.com/jrom/jrom10'&gt;two&lt;/a&gt;). Then, I&amp;#8217;ve coded blog engines in PHP by myself (the source code is lost), using Rails (never finished) and Sinatra (first version using a database and coded from scratch &lt;a href='http://github.com/jrom/jromrb'&gt;here&lt;/a&gt;). I&amp;#8217;m sure I forgot some weekend projects done some years ago.&lt;/p&gt;

&lt;p&gt;And now, this one. What&amp;#8217;s special about this blog? Well, it&amp;#8217;s the latest. And the prettiest. And is build as a &lt;strong&gt;Sinatra&lt;/strong&gt; application using &lt;strong&gt;Git&lt;/strong&gt; to store the posts. I discovered &lt;strong&gt;&lt;a href='http://effectif.com/nesta'&gt;Nesta&lt;/a&gt;&lt;/strong&gt; a couple of months ago thanks to the &lt;a href='http://blog.peepcode.com/tutorials/2010/about-this-blog'&gt;Peepcode blog&lt;/a&gt;. I cloned it and built this blog on top of it. I took the look and feel I already designed in my latest Sinatra blog (the one with the database that never got to see the sunlight) and &lt;em&gt;voilà&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Besides from loading all the content from static files (pushed via Git), this blog features an awesome &lt;em&gt;non-existent&lt;/em&gt; admin section, some very nice page caching (using the neat &lt;a href='http://github.com/kematzy/sinatra-cache'&gt;sinatra-cache&lt;/a&gt; extension by Kematzy) to prevent loading the Ruby stack, a &lt;a href='/articles.xml'&gt;feed&lt;/a&gt; and a &lt;a href='/sitemap.xml'&gt;sitemap&lt;/a&gt;. Oh, and the content is formatted using &lt;a href='http://daringfireball.net/projects/markdown/'&gt;Markdown&lt;/a&gt; (almost everywhere) and &lt;a href='http://haml-lang.com/'&gt;Haml&lt;/a&gt; (where the layout may be trickier). For the stylesheet generation, Haml&amp;#8217;s sister is used: &lt;a href='http://sass-lang.com/'&gt;Sass&lt;/a&gt;. There&amp;#8217;s some code highlighting capabilities thanks to &lt;a href='http://softwaremaniacs.org/soft/highlight/en/'&gt;highlight.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is one feature I haven&amp;#8217;t implemented yet, but will do soon: &lt;strong&gt;comments&lt;/strong&gt;. This blog now is using no database to work, and everything is page-cached when the first request arrives, so a traditional comments functionality would fuck everything up a little&amp;#8230; unless I use some service like Disqus or Itense debate. I don&amp;#8217;t like these services (if there&amp;#8217;s a better alternative, please &lt;a href='/contact'&gt;tell me&lt;/a&gt;), so I will have to code some mini-disqus-like web-service to feed my own blog&amp;#8217;s comments. I&amp;#8217;ll keep you posted.&lt;/p&gt;</content>
    <published>2010-04-27T23:00:00-07:00</published>
    <updated>2010-04-27T23:00:00-07:00</updated>
    
  </entry>
  <entry>
    <title>Hi... again</title>
    <link type="text/html" href="http://jrom.net/hi-again" rel="alternate"/>
    <id>tag:jrom.net,2010-04-27:/hi-again</id>
    <content type="html">&lt;p&gt;Hi, I&amp;#8217;m &lt;a href='/about'&gt;Jordi Romero&lt;/a&gt;. This is a blog, or it&amp;#8217;s supposed to be, where I can publish anything I may find useful. The subjects will vary, from programming to computer architecture, or maybe some &lt;em&gt;sysadmin&lt;/em&gt; trick that took me all night to find out and want to share to make the world a better place. Time will tell.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m trying to have and maintain a blog since &lt;strong&gt;2004&lt;/strong&gt;! In 6 years I never published more than 20 posts, most of which never stayed online after some months. I started blogging in Catalan, my first language. Later on 2006 I deleted the blog and replaced it with a static &lt;acronym title='Curriculum Vitae'&gt;CV&lt;/acronym&gt; in the front page (the first screenshot). One year later I started a &lt;em&gt;new&lt;/em&gt; version of the blog (the right image) in Spanish, my second language. I published some useful Ruby on Rails tutorials, and an article about my &lt;a href='http://en.wikipedia.org/wiki/File:Happy_Hacking_Keyboard_Professional_2.jpg' title='Happy Hacking Keyboard Professional 2'&gt;keyboard&lt;/a&gt; that got some attention. Sincerely, nothing worth saving or translating to this &lt;em&gt;newer&lt;/em&gt; version. Some good and interesting content is out there, and I will write it down.&lt;/p&gt;
&lt;img class='center no-margin' src='/files/hi-again/jrom.jpg' alt='jrom.net when it was a CV in catalan' /&gt;&lt;img class='center no-margin' src='/files/hi-again/jrom-2.jpg' alt='jrom.net when it was a blog in spanish' /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;If you just want to say something to me, make sure you check the &lt;a href='/contact'&gt;contact&lt;/a&gt; page.&lt;/p&gt;</content>
    <published>2010-04-27T22:00:00-07:00</published>
    <updated>2010-04-27T22:00:00-07:00</updated>
    
  </entry>
  
</feed>


