These days Twitter Bootstrap seems to be the new hype for front-end work. It’s so popular that it makes you forget there are other frameworks out there. And while there surely is a reason for bootstrap’s popularity, it might not be the best fit for your project. Sometimes you want something more generic, elegant and flexible.
You want to write CSS yourself. You want control over every line of code. You want Susy.
Susy is a set of Sass and Compass extensions to make responsive design easy for you. It is packaged as a ruby gem, so inclusion in your project means adding a line to your Gemfile!
So it’s another bootstrap? No, it gives you the power to roll your own bootstrap quickly. And that might be a blesing or a curse, depending on your skill, your project and time constraints.
I assume you already use compass and you are familiar using Sass (or LESS). Susy uses grids to define your layout. And a grid has

Enough talk for now, let’s start coding! We start by creating a simple html file containing the grid.
With the following css:
When viewed on a desktop computer:
When viewed on a tablet or phone:
Since Susy uses Sass, we need to make sure we get a working Sass environment.
# install compass
$ gem install compass
# initialise the project
$ cd path/to/project
$ compass init
# create the scss file
$ touch sass/style.css.scss
# compile
$ compass compile
Now that Compass and Sass are ready, we are ready to create our first SCSS files.
We’ll use a mobile-first approach (as documented by susy) and we start off by setting variables to initialise the Susy-grid:
$total-columns: 6;
$column-width: 40px;
$gutter-width: 10px;
$grid-padding: 5px;
// 6 * 40px + 5 * 10px + 2 * 5px = 300px
// $total-columns * $column-width + ($total-columns - 1) * gutter-width + 2 * $grid-padding = container width
#container {
padding: 5px;
background-color: black;
}
#main {
padding: 5px;
background-color: #F99;
}
#side {
padding: 5px;
background-color: #99F;
}
Because we’ve done nothing more than setting some variables, we can’t expect any change in output. We don’t use these variables yet…
Add Susy to your config.rb in compass. If you like an example, here is my config.rb.
Instruct Sass to import the Susy library. We do this by using an @import command. Example: @import “susy”
Use functions in the susy library do define our columns and containers. We do this using @include.
Now we’ll add the definitions for our grid. Like this:
$total-columns: 6;
$column-width: 40px;
$gutter-width: 10px;
$grid-padding: 5px;
// 6 * 40px + 5 * 10px + 2 * 5px = 300px
// $total-columns * $column-width + ($total-columns - 1) * gutter-width + 2 * $grid-padding = container width
@import "susy";
$break-desktop: 15;
#container {
padding-top: 5px;
padding-bottom: 5px;
background-color: black;
@include container;
}
#main {
background-color: #F99;
@include span-columns($total-columns);
}
#side {
padding: 5px;
background-color: #99F;
display: none;
}
And you end up with this result. Exactly the mobile layout we had in our mind when designing the website.
Now we’ll add the responsive mix-ins to make an alternate desktop layout.
And now we end up with this file:
$total-columns: 6;
$column-width: 40px;
$gutter-width: 10px;
$grid-padding: 5px;
// 6 * 40px + 5 * 10px + 2 * 5px = 300px
// $total-columns * $column-width + ($total-columns - 1) * gutter-width + 2 * $grid-padding = container width
@import "susy";
$break-desktop: 15;
#container {
padding-top: 5px;
padding-bottom: 5px;
background-color: black;
@include container($total-columns, $break-desktop);
}
#main {
background-color: #F99;
@include span-columns($total-columns);
}
#side {
background-color: #99F;
display: none;
}
@include at-breakpoint($break-desktop) {
#main {
@include span-columns($break-desktop - 5, $break-desktop);
}
#side {
@include span-columns(5 omega, $break-desktop);
display: block;
}
}
Using these mix-ins we have now created a solution which uses the desktop layout if possible, and otherwise switches to the mobile layout. If you only see the desktop version, try resizing your browser window. You are now ready to start your first responsive design.
Good luck!

Remember the upstream block from last post’s Nginx config file? That’s what we’ll be configuring today. For your convenience I’ll include the snippet of the config here:
upstream app_server {
server unix:/tmp/yoursite.sock fail_timeout=0;
}
For the Ruby webserver, I prefer Unicorn, but it doesn’t really matter. You could use any other and you still get a working web application. That being said, this post assumes your using unicorn.
Make a config file, called unicorn.rb (Yes, it’s ruby code) and put it in the config/ directory of your rails project. Now paste the following snippet into the config.
1#Unicorn minimal configuration 2worker_processes 1 3preload_app true 4timeout 30 5 6#Use your rails application name here 7listen '/tmp/yoursite.sock', :backlog => 1024 # 2007 8 9pid "tmp/pids/unicorn.pid" 10 11#set up the log paths 12stderr_path "log/unicorn.stderr.log" 13stdout_path "log/unicorn.stdout.log" 14 15after_fork do |server, worker| 16 ActiveRecord::Base.establish_connection 17end
The most important thing is that the server line in your nginx-config matches the listen line in unicorn.rb.
Because we use unicorn, our rails project needs the unicorn gem in it’s Gemfile. If it’s not already there, you should add it. Now all that’s left for you to do is to start the ruby webserver. This is done by these commands:
$ cd /path/to/your/rails/app_root
$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D
This command executes “unicorn_rails -c config/unicorn.rb -E production -D” in the correct environment. Bundle exec makes sure the correct versions of the gems are loaded and installed.
The unicorn_rails command starts the webserver. It’s options are
My previous FTP-script is a very usefull tool for updating new websites. But what if you just want to mirror a remote ftp to a local folder? You can’t. So I made some modifications to it.
On google I found various solutions pointing to ncFTP but I don’t like installing custom software on my Macbook. Only appstore or open source please.
A script which puts or gets all the files from local folder to a remote directory. Something I can call like this:
$ r-ftp p /folder/ ftp://user:password@remote.com/pub/
With two possible values for the first commandline option:
And a little bit later r-ftp (for Section R - Ftp) is born:
1#!/usr/bin/env ruby 2require 'net/ftp' 3require 'fileutils' 4 5# documentation 6def usage 7 puts "r-ftp COMMAND LOCAL REMOTE" 8 puts " COMMAND" 9 puts " g: GET copy from remote to local" 10 puts " p: PUT copy from local to remote" 11 puts " LOCAL local directory" 12 puts ' REMOTE ftp-server in format "ftp://username:password@host/directory"' 13 puts '' 14 puts 'EXAMPLE' 15 puts ' Get all files from a ftp server with a folder' 16 puts ' r-ftp g /home/user/dump/ ftp://example.org/pub/' 17 exit 18end 19 20# put recursively all files from path to the ftp server 21def put(path, ftp) 22 Dir.entries(path).each do |file| 23 next if ['.', '..'].include? file 24 25 file_path = path + '/' + file 26 if File.directory?(file_path) 27 ftp.mkdir(file) unless ftp.nlst.index(file) 28 ftp.chdir(file) 29 put(file_path, ftp) 30 ftp.chdir('..') 31 else 32 puts "Put: " + file_path 33 ftp.putbinaryfile(path + '/' + file) 34 end 35 end 36end 37 38# get recursively all files from path to the ftp server 39def get(path, ftp) 40 initial_path ||= path 41 ftp.nlst.each do |file| 42 next if ['.', '..'].include? file 43 44 file_path = path + '/' + file 45 if ftp_directory?(ftp, file) 46 FileUtils.mkdir(file_path) unless File.directory?(file_path) 47 ftp.chdir(file) 48 get(file_path, ftp) 49 ftp.chdir('..') 50 else 51 puts "Get: " + ftp.pwd + "/" + file 52 ftp.getbinaryfile(file, file_path) 53 end 54 end 55end 56 57#helper function to check if a file on a ftp-server is a directory 58def ftp_directory?(ftp, file_name) 59 ftp.chdir(file_name) 60 ftp.chdir('..') 61 true 62rescue 63 false 64end 65 66# returns a hash with the correct data from server string 67def parse_ftp_format server 68 matchdata = /ftp:\/\/((?<username>[[:alnum:]]*)[:,@])?((?<password>[[:alnum:]]*)@)?(?<server>[\w\d\.]+\.[[:alnum:]]{2,})(?<target>\/.*)?/.match(server) 69 return nil unless matchdata 70 return Hash[ matchdata.names.zip matchdata.captures ] 71end 72 73usage if not (ARGV[0] and ['g', 'p'].include? ARGV[0] and ARGV[1] and File.directory?(ARGV[1]) and ARGV[2] and (ftp_server = parse_ftp_format ARGV[2])) 74 75puts ftp_server.to_s 76 77#initialise ftp connection 78ftp = Net::FTP.new(ftp_server['server']); 79ftp.login(ftp_server['username'], ftp_server['password']) 80ftp.chdir(ftp_server['target']) 81 82# is it get or put? 83if ARGV[0] == 'g' 84 get ARGV[1], ftp 85else 86 put ARGV[1], ftp 87end 88 89ftp.quit 90
If you have downloaded this script you can install it with these commands:
$ chmod +x /path/to/r-ftp.rb
$ sudo mv /path/to/r-ftp.rb /urs/local/bin/r-ftp