Logging and showing colorful bash output

Deploy using the deploy user and also log who deploys using the original user.
Retaining the color was tricky but script fakes tty so we can keep all the color glory and with sed we strip colors before logging them.

# /usr/bin/capsu
function log {
  old_IFS=$IFS
  IFS='' # do not split on newline when reading stdin
  newline=$'\n'
  line=""

  while read -d '' -n1 c # read every character
  do
    # print every character as it comes in for cap shell and password prompts
    printf "%s" "$c"

    # amend complete line with current user (but without color codes) to log
    # so multiple people can run capsu in parallel
    if [ "$c" = $newline ]; then
      echo "$SUDO_USER: $line" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" >> $1
      line=""
    else
      line+=$c
    fi
  done
  IFS=$old_IFS
}

rvmsudo -u deploy script /dev/null -c "bundle exec cap $@" 2>&1 | log deploy cap.log

Prevent missing type / NameError in polymorphic ActiveRecord associations

ActiveRecord loads the xxx_type in your model, making it blow up when doing includes / using the belongs_to on a missing type.
So we make it un-missing.

Usage

class Waldo < MissingType
end

Code

class MissingType < ActiveRecord::Base
  default_scope :conditions => "1 = 2", :limit => 0

  self.table_name = "schema_migrations"

  def self.primary_key
    "version"
  end

  def readonly?
    true
  end
end

Kill ActiveRecord observers

Killing observers

  • decreases startup time by not loading all your models
  • makes it possible to preload config/environment.rb and still test models -> spin/zeus
  • makes dependencies obvious
  • replaces ActiveRecord magic with ruby
  • makes your app Rails 4 ready

Before:

# config/environment.rb
config.observers = [:foo_observer] 

# app/observers/foo_observer.rb
class FooObserver < ActiveRecord::Observer
  observes :user

  def after_save(user)
    ....
  end
end

After:

# app/models/user.rb
class User < ActiveRecord::Base
  include FooObserver
end

# app/observers/foo_observer.rb
module FooObserver
  class << self
    def included(base)
      this = self
      base.after_save{|user| this.more_descriptive_name(user) }
    end

    def more_descriptive_name(user)
      ...
    end
  end
end

Upgrading to rails 3.0 — making sure you use rack headers everywhere

Normal headers like Accept or :authorization do not work in rails 3 integration tests and you need to convert everything to HTTP_ACCEPT etc, to help find all those places and make sure you do not introduce new bugs in rails 2 add this:

# https://grosser.it/2012/10/19/upgrading-to-rails-3-0-making-sure-you-use-rack-headers-everywhere/
# message can be changed on rails 3, but keep the warning, it's so hard to track down missing headers
# maybe try to remove in rails 3.1+
# can be tested by e.g. changing header to Accept instead of HTTP_ACCEPT
class ActionController::Integration::Session
  # headers that are only used by our code and not rails/rack can be whitelisted, but make sure they work on rails 2 and 3
  HEADER_WHITELIST = ['Funky-Headers-You-Have-To-Use']
  def process_with_header_warning(*args)
    if args[3] && bad = args[3].keys.detect{|k| !k.is_a?(String) || (!HEADER_WHITELIST.include?(k) && k !~ /^[A-Z_\d]+$/) }
      raise "Header #{bad} will not work on rails 3, please uppercase (Content-Type -> CONTENT_TYPE) and prefix HTTP_ (Accept -> HTTP_ACCEPT)"
    end
    process_without_header_warning(*args)
  end
  alias_method_chain :process, :header_warning
end