Jim Neath

Manchester based Ruby on Rails & Facebook App Developer

While the Asset Pipeline introduced in Rails 3.1 is awesome, it can be slow if you are precompiling on deploy time. To get around this, you can compile your assets on your local machine and commit them to your repo.

To automate the process, I wrote a small pre-commitGit hook that runs rake assets:precompile:all if any assets have been changed then adds the results to the current commit.

To use simply copy the code below into .git/hooks/pre-commit inside of your Rails application.

#!/bin/bash

# source rvm and .rvmrc if present
[ -s "$HOME/.rvm/scripts/rvm" ] && . "$HOME/.rvm/scripts/rvm"
[ -s "$PWD/.rvmrc" ] && . "$PWD/.rvmrc"
 
# precompile assets if any have been updated
if git diff-index --name-only HEAD | egrep '^app/assets' >/dev/null ; then
  echo 'Precompiling assets...'
  rake assets:precompile:all RAILS_ENV=production RAILS_GROUPS=assets
  git add public/assets/*
fi

Update: As mentioned by jrochkind in the comments, you will probably want to add the following to your config/environments/development.rb:

config.assets.prefix = '/assets_dev'

This will prevent your local application from serving the static assets from public/assets/ when running in development.

Ruby SSL Certificate Verify Failed

If you’re using Ruby to open connections to an external server over https, eg. the Facebook Graph API, you may run into the following error:

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

This error is due to Ruby not being able to find the certification authority certificates (CA Certs) used to verify the authenticity of secured web servers. The solution is to download the this ca-bundle.crt into your application’s lib/ directory:

Then add the following code to config/initializers/fix_ssl.rb:

require 'open-uri'
require 'net/https'

module Net
  class HTTP
    alias_method :original_use_ssl=, :use_ssl=
    
    def use_ssl=(flag)
      self.ca_file = Rails.root.join('lib/ca-bundle.crt')
      self.verify_mode = OpenSSL::SSL::VERIFY_PEER
      self.original_use_ssl = flag
    end
  end
end

This should force ruby to use the CA bundle from your application’s lib/ directory.

Party on, Wayne!

The standard way of deploying rails applications is to serve a static maintenance page while the code is being updated, to prevent errors being thrown by the user and to prevent writes happening to your database. This is all fine and dandy in the real world but in Facebook land we run into issues.

Facebook will always send a POST on the initial iframe request for security reasons, and this can be to any end-point in our application, while in reality, this should be treated as a GET.

So, the first time a page of your app is requested by user, Facebook sends a POST request. If you’re currently in maintenance mode you’re going to get a big 405 Method not allowed error.

To fix this we need to tell nginx to serve your maintenance page to POST requests, as well as GET requests. We can do this by updating your servers config files. Say your server config initially looks like this:

server {
  # all your other server stuff
  # ...

  # show maintenance page if exists 
  if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html break;
    break;
  }
}

Add the following location rule to allow nginx to serve the page for POST requests:

server {
  # all your other server stuff
  # ...

  # show maintenance page if exists 
  if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html break;
    break;
  }

  # serve maintenance page to POST requests
  location = /system/maintenance.html {
    post_to_static on;
  }
}

Reload your nginx config and everything should be rocking as expected.

I am available for freelance work! Click here to email me.

Jim Neath is a Freelance Ruby on Rails & Facebook app developer from Manchester, UK, currently working for Engine Yard.