Skip navigation

Active Product Development

3 Posts tagged with the rails tag

The general internet discovered Unicorn after a blog post over at GitHub. I've been wanting to use it for a while now. Early this week we switched over Trainer 2 to this awesome web server.


The idea behind Unicorn is that instead of having a separate load balancer with all kinds of fancy rules to determine which workers are busy and which are available to do some work, you let the tried and true process management built into your OS do that work for you. Unicorn consists of a master process that spawns workers. The master monitors the workers and kills and restarts any that are behaving badly. When a request comes in the master hands it off to the operating system to determine which worker process has the resources available to work on it. The stack looks like this:

You stil want to keep your web server (nginx in our case, or Apache) serving static content. You just let the server know where to pass all the other requests to. In nginx this looks something like:


upstream trainer2 {
  server unix:/tmp/unicorn.sock fail_timeout=0;
server {
  listen 80;
  root /var/www/current/public;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_max_temp_file_size 0;

    # serve static content with a far-future expires header
    location ~ ^/(images|stylesheets|javascripts)/ {
      expires 10y;

    # if the file exists (static stuff) serve it right away
    if (-f $request_filename) {

    # otherwise pass it on to unicorn
    if (!-f $request_filename) {
      proxy_pass http://trainer2;



That's it for nginx. Now to start up Unicorn you need a config file (ours is in /config/unicorn.rb):


# Sample verbose configuration file for Unicorn (not Rack)
# This configuration file documents many features of Unicorn
# that may not be needed for some applications. See
# for a much simpler configuration file.
# See for complete
# documentation.

root = '/var/www/current'

worker_processes(ENV['RACK_ENV'] == 'production' ? 8 : 2)
working_directory root # available in 0.94.0+
listen "/tmp/unicorn.sock"
timeout 120

pid "#{root}/tmp/pids/"

stderr_path "#{root}/log/unicorn.stderr.log"
stdout_path "#{root}/log/unicorn.stdout.log"

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  old_pid = "#{root}/tmp/pids/"
  if File.exists?(old_pid) && != old_pid
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection



Now we just start up Unicorn like so (from our application's root directory):


unicorn -E production -c config/unicorn.rb -D


And that's it! You should be able to hit your server and have Unicorn respond. The true magic starts when you want to do a deploy: you don't have to have any downtime because Unicorn will start up a new master while the old one continues to serve clients. Once the new master is up and running, the first worker it spawns will turn off the old master. Users never saw a delay and you were able to upgrade your app transparently. Using this technique you can upgrade Unicorn itself, or even Ruby with no downtime! To trigger this restart just send the USR2 signal to Unicorn. First, run a ps aux | grep unicorn to get the process list and send the signal to the existing master process:


ubuntu@qa:~$ ps aux | grep unicorn

ubuntu   23511  0.0  4.0  80216 71040 ?        Sl   May04   0:15 unicorn master -E qa -c config/unicorn.rb -D                                    
ubuntu   23641  0.0  5.0  99108 88576 ?        Sl   May04   0:51 unicorn worker[0] -E qa -c config/unicorn.rb -D                                 
ubuntu   23644  0.0  5.0  98004 87632 ?        Sl   May04   1:14 unicorn worker[1] -E qa -c config/unicorn.rb -D

ubuntu@qa:~$ kill -USR2 23511


After a few seconds (however long it takes for your Rails app to start) you'll begin serving your new code. Done!

1,898 Views 0 Comments Permalink Tags: trainer, ruby, rails, unicorn

ActiveRecord is great but it can be a little scary to think about using it without Rails. Here's a quick example of using it with Sinatra.


The first thing we'll want to do is get the ActiveRecord gem by itself (throughout this tutorial I'm assuming you're using Bundler to manage your gems):


gem 'activerecord', :require => 'active_record'


Next up, in the configure block of our Sinatra app, we'll set up the AR connection to our database:


ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'db/development.db')


Of course, if you want to stay flexible, you can move your database config into a YAML file (laid out the same as the Rails standard config/database.yml file) and pull the connection details from that:


db_config = YAML::load(,'config','database.yml')))[Sinatra::Application.environment]

Now that AR is ready to go we can include our models. I like to move my models into separate files, similar to Rails's app/models, so I tell Sinatra to include every file in that directory:


Dir.glob('./app/models/*').each { |r| require r }


Believe it or not, that's really all you need to do to start using AR in your Sinatra application! The only missing link is database migrations. AR comes with a huge Rake file full of tasks like db:migrate, but unfortunately those rely on being inside the shell of Rails (they look for environment variables like RAILS_ENV and the base Rails object all over the place). Here's a very simple piece of code that will enable the standard db:migrate task:


require 'bundler'

desc "Migrate the database through scripts in db/migrate."
task :migrate do
  ActiveRecord::Base.establish_connection(YAML.load('config','database.yml')))[ENV['ENV'] ? ENV['ENV'] : 'development'])


This assumes that your migration files are in db/migrate. When you want to migrate in an environment other than development just set the ENV variable:


rake db:migrate ENV=production


That's it! There are a couple of different database ORM libraries out there besides ActiveRecord (like Sequel and Datamapper) but AR is the most popular today and it's easy to use it in all of your web apps, whether they're Rails or not.

10,436 Views 0 Comments Permalink Tags: ruby, sinatra, rails, database, activerecord

Ruby on Rails comes with a bunch of great rake tasks to help you work with your application. One of them is rake stats which counts the lines of code in your controllers, models and tests. It's a pretty neat utility that we use all the time to make the Java developers jealous.


I've been working on a little Sinatra application and wanted to use the same functionality. The rake stats command used the CodeStatistics class from one of the core Rails packages called railties (that's "rail-ties" as in the wooden slats that hold up train tracks, not "rail-tees" like t-shirts about trains). Now, the good Ruby developer in me says to simply require 'railties/code_statistics' from in my Sinatra application. However, I also realize that my Sinatra application has nothing to do with Rails and never will. So I did the unthinkable: copy-paste. In this case I don't think it's that bad: code_statistics probably hasn't changed much since Rails 1.0 and it's not something that I care about keeping in sync with the master development branch of Rails. Don't sweat it.


I put code_statistics.rb in a new directory in my Sinatra app called vendor which is a Rails convention for code from third-parties. Normally I would just put this code into lib, but in this case rake stats includes the lines of code in any files in lib, and I didn't want to throw off my numbers. In my Rakefile I added a new task (also copied from the Rails default Rakefile with a couple modifications):

desc "Report code statistics" task :stats do   require './vendor/code_statistics'     STATS_DIRECTORIES = [     %w(Controllers        app/controllers),     %w(Helpers            app/helpers),     %w(Models             app/models),     %w(Libraries          lib/),     %w(Migrations         db/migrations),     %w(Views              app/views)   ].collect { |name, dir| [ name, "./#{dir}" ] }.select { |name, dir| }*STATS_DIRECTORIES).to_s end


The modifications in this case are the directories that should be scanned for code lines. By default Rails doesn't include your views as counting towards your totals, but I wanted them to. I also have lots of migrations and would like to know how those contribute as well.  If you have any directories in addition to these just add them to the STATS_DIRECTORIES constant. I also wanted to count the number of comments in my code. I'm a big proponent of commenting and I'd like to know what ratio of my code is used to tell my future self how everything works. You can get a copy of my code_statistics.rb file (with comment-counting mods) here:


And that's it! Now just rake stats from the root of your Sinatra app and you'll see something like this:


+----------------------+-------+-------+----------+---------+---------+-----+-------+ | Name                 | Lines |   LOC | Comments | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+----------+---------+---------+-----+-------+ | Controllers          |    65 |    50 |        8 |       0 |       0 |   0 |     0 | | Helpers              |    41 |    32 |        0 |       0 |       7 |   0 |     2 | | Models               |    12 |    10 |        0 |       2 |       1 |   0 |     8 | | Libraries            |     8 |     6 |        1 |       2 |       1 |   0 |     4 | | Migrations           |    78 |    71 |        4 |       0 |       0 |   0 |     0 | | Views                |    45 |    39 |        0 |       0 |       0 |   0 |     0 | +----------------------+-------+-------+----------+---------+---------+-----+-------+ | Total                |   249 |   208 |       13 |       4 |       9 |   2 |    21 | +----------------------+-------+-------+----------+---------+---------+-----+-------+   Code LOC: 208     Test LOC: 0     Code to Test Ratio: 1:0.0


853 Views 0 Comments Permalink Tags: ruby, sinatra, rails, rake