Ruby Fleebie

Rediscovering the joy of programming

How To Strip Insignificant Zeros From a Float In Rails

I had a float attribute in a Rails application and wanted to strip non-significant zeros when displaying it on a page. With the number_with_precision helper from ActionView, that’s a trivial thing:

number_with_precision(
  3.50,
  strip_insignificant_zeros: true,
  precision: 2
)
# => "3.5"

How to hook to an Array instance in a Ruby module

On some project we needed to create a module containing an Array attribute. We wanted to hook onto some of the methods of this particular Array instance to call our own code. Here is how we did it:

module TheModule
  attr_reader :items
  def initialize(*args)
    @items = []

    def @items.<<(item)
      super
      "You added the item #{item} with <<!"
    end

    def @items.push(item)
      super
      "You added the item #{item} with push!"
    end
    super
  end
end

class TheClass
  include TheModule
end

And now the output:

x = TheClass.new
x.items   # => []
x.items << 'blue' # => You added the item 'blue' with <<!
x.items.push 'orange' # => You added the item 'orange' with push!
x.items # => ["blue", "orange"]

Every Little Things Capistrano Does Is Magic

During all these years, Capistrano has been for me a magical gnome that I invoke by saying “cap deploy, my magical friend!” and then I close my eyes, sing a happy song in my head and when the gnome has finished his magic, I hit F5 to see if all went well. And of course, if it didn’t, I blame the damn elf.

I am proud of this introduction. I will take a sip of coffee and read it again, hold on. Yes this intro was good, I think I should write about magical little beings more often.

If you are like me, you never paid much attention to capistrano and the way it works. At the exception of the famous “cap deploy” command, you never really wanted to get involved in the process. For this reason you have copied and pasted the same old deployment recipe in all of your projects over the years, only changing some parameters like the application name and the emplacement of the git repository.

The fact that capistrano is doing magical things doesn’t really help in this regard. My goal in this post is to explain some of the not so obvious parts of capistrano. With minimal efforts we can have a better idea of what capistrano does and feel more in control when deploying an application.

Capistrano is magic

Like many things in the ruby world, there is a fair bit of magic involved in capistrano. For example, when you type “cap deploy”, there is a bunch of things that happen, but what things exactly? What tasks are being called? This is not obvious. First of all, “deploy” is not a task written in your own recipe file, it is a namespace located in the capistrano gem. Take a look:

namespace :deploy do
  desc <<-DESC
    Deploys your project. This calls both `update' and `restart'. Note that \
    this will generally only work for applications that have already been deployed \
    once. For a "cold" deploy, you'll want to take a look at the `deploy:cold' \
    task, which handles the cold start specifically.
  DESC
  task :default do
    update
    restart
  end
#...

As you can see, the :default task is invoked when you type “cap deploy”, which in turns will call “update” and “restart”.

This is why you never got to see a call to the :restart task in your own recipe file. I know that during all these years there was a secret part of your brain that was¸wondering about this stuff, while the not-so-secret part really didn’t care.

Capistrano and Bundler

  require 'bundler/capistrano'

This line adds some bundler magical stuff to your recipe. It will install your bundle (with the –deployment flag) when deploying, meaning that all your gems will be vendored to yourapp/shared/bundle.

Capistrano and the Asset Pipeline

load "deploy/assets"

This line adds some magical stuff for compatibility with the Rails 3.1+ asset pipeline. More precisely, it will precompile your assets. This is an almost essential part when you use the asset pipeline in production. The other solution is to precompile locally and push the assets to your repository, not a good idea in my opinion. The sad part is that precompiling assets can slow down your deployment quite severly. If you use GIT, you might like this smart solution from Ben Curtis to skip assets precompilation.

Capistrano and RVM

$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
require "rvm/capistrano"
set :rvm_ruby_string, 'ruby-1.9.2-head@rails3.2'
set :rvm_type, :user

This tells capistrano to switch to a specific ruby version + gemset when connected to the server. The gemset (i.e. @rails3.2) is the tricky part because it makes you think that, when capistrano will invoke bundle install, your gems will be installed in .rvm/gems/ruby-1.9.2-head@rails3.2/gems. This is not the case. Remember that we have just told bundler to install the gems in yourapp/shared/bundle/.

So why do we bother with the gemset anyway?

One reason is that the bundler gem itself will be invoked by capistrano on your server in the gemset specified in the rvm_ruby_string variable. It can be useful to specify a gemset if you want to use a specific version of bundler.

That's all folks!