Rails’ symbols for HTTP status codes

This is more of a personal reference than anything ground-breaking. I found this in a comment to the render method on ApiDock. Some pretty bad wording there, anyone with a who | grep -i blonde | date; cd ~; unzip; touch; strip; finger; mount; gasp; yes; uptime; umount; sleep like comment? ;)
Read the rest of this entry »

Vivaldi’s Four Seasons for free?

I was surprised to see the wikipedia page for Vivaldi’s Four Seasons to have freely available Ogg/Vorbis files. I know I could have downloaded them all manually, yes. However, I thought it to be a good evening sport to write a small script that downloads it for me and converts the OGG files (not much liked by iTunes) into MP3 (it also sets ID3-tags with a bit of awk-magic).
The result can be found below (or download the script directly). It requires the rubygem Nokogiri and expects the command line tools ogg123, vorbiscomment (both available in a packaged named “vorbis-tools” on Macports) and lame (MP3 encoder) to be installed in your $PATH.

Obligatory legal stuff: the file comes “as is” with no warranty whatsoever. The downloaded files are from John Harrison and licensed under the Creative Commons Attribution-Share-Alike Generic 1.0 License. The script itself is hereby released as beer-ware.

The script is brittle: if Wikipedia decides to change their link styles, all hell breaks loose. It may or may not work for you – YMMV. But here goes:

#!/usr/bin/env ruby
 
require 'rubygems'
require 'open-uri'
require 'nokogiri'
require 'net/http'
 
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"
url = "http://en.wikipedia.org/wiki/The_Four_Seasons_%28Vivaldi%29"
fourseasonspage = Nokogiri::HTML(open(url, "User-Agent" => user_agent))
 
@destdir = ENV['DESTDIR'] || 'vivaldi'
FileUtils.mkdir_p(@destdir) unless File.exists?(@destdir)
 
@uri = URI.parse(url)
 
# Aquiring the Four Seasons
puts "\e[1mGetting Files...\e[0m"
puts
 
fourseasonspage.css("div.medialist a").each do |ogg_link|
  url = "http://"+ @uri.host + ogg_link[:href]
  ogg_page = Nokogiri::HTML(open(url, "User-Agent" => user_agent))
 
  ogg_page.css("div.fullMedia a.internal").each do |link|
      puts "Downloading: " + link[:href]
      filename = File.basename(link[:href])
      uri = URI.parse(link[:href])
      Net::HTTP.start(uri.host) do |http|
        resp = http.get(uri.path)
        open(File.join(@destdir, filename), "wb") do |file|
          file.write(resp.body)
        end
      end
  end if /File:/.match(ogg_link[:href])
end
 
# Now comes cmd line file converting
puts "\e[1mStarting conversion...\e[0m"
puts
 
`for file in #{@destdir}/*.ogg ; do \
  echo > id3.tag; \
  vorbiscomment -l -e $file |awk -F= '{print $1"=""'\''" $2 "'\''" }' > id3.tag ; \
  source id3.tag; \
  ogg123 -d wav -f - $file \
  | lame -h -v -m s -b 192 --tt "$title" --tn "$tracknumber" --ta "$artist" --tg "$genre" --tc "$comment" --tl "$album" --id3v2-only - #{@destdir}/$(basename "$file" .ogg).mp3; \
done; rm id3.tag`
 
puts "\e[1mAll done.\e[0m"
puts "(You may wish to delete #{@destdir}/*.ogg)"

Getting started:

DESTDIR=path/to/dir ruby vivaldi.rb

assert_select from string

ActionController::TestCase provides assert_select to check for specific contents of views in a Rails project. It’s also a nice way to test view helpers with somewhat more complex HTML output (ie. nested nodes by multiple calls to content_tag).

There is a nice and short article by Erik Ostrom that explains how to do that without the response object you’ll normally have when using it to check views. However, it lacked support for nested nodes which can be remedied by adding yield @selected if block_given?.

The modified code snippet to put in test/test_helper.rb is:

class ActiveSupport::TestCase
  def assert_select_from(text, *args)
    @selected = HTML::Document.new(text).root.children
    assert_select(*args)
    yield @selected if block_given?
  end
end

Usage:

def test_hreview_aggregate_item
  output = hreview_aggregate(:fn => "John Doe's Pawn Shop")
  assert_select_from output, "span.hreview-aggregate" do
    assert_select "span.item" do
      # nb: it's assert_select within the block
      assert_select "span.fn", :text => "John Doe's Pawn Shop"
    end
  end
end

HAProxy, X-HTTP-Forwarded-For, Rails and exposed exceptions

(A german version is available at the kaupert media gmbh website)

We use HAProxy as the frontend to forward incoming requests to Apache+Passenger instances on our webservers at berlin.kauperts.de.

Problems arose on the HAProxy machine itself which was also (intentionally) forwarding requests to a locally running Apache: despite using the forward_for option for the configured backend, Rails considered all incoming requests local as they were indeed coming from the local machine. The result was exposed exceptions, even on something as trivial as RoutingError which should trigger a normal 404.

Wesley Moxam described this problem in a blog post, but our setup is slightly different: HAProxy sends requests directly to Passenger/mod_rails within Apache vhosts without Apache-side (double)proxying involved. Removing the option forwardfor as described in said post was no viable way to go for us as it confused the non-local nodes in the setup.

Additionally, the Rails applications on each node behind HAProxy would never get the true client’s IP address: Request#remote_ip was always that of the HAProxy instance.

Heaving the formally locally running instance onto the external interface and treating it just as any other node rid us of the first problem and adding your HAProxy to the list of TRUSTED_PROXIES fixes the second. Add the following line as an initializer to your Rails 2.3.x app. The HAProxy backend uses option httpclose and option forward_for.

# config/initializers/trusted_proxies.rb
# If your HAProxy is running at 209.85.149.104, set:
ActionController::Request.const_set("TRUSTED_PROXIES", /^209\.85\.149\.104$|^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i)

Granted, I don’t feel overly comfortable with coding that bit of network architecture into my Rails application. Moving servers and switching IPs is pain enough as it stands and thus I don’t like adding another dependency. It works, though, and here’s to hoping that our loadbalancer does not have to be exchanged anytime soon.

amatch gem on Ubuntu 10.4 x64_86

Setting up a new server, I’ve run into another gem building problem (similar to a problem with the mysql gem on a Centos 5.2 system a while back). The amatch gem fails to build its native part on a 64bit Ubuntu, terminating with:

/var/lib/gems/1.8/gems/amatch-0.2.5/lib/amatch.so: wrong ELF class: ELFCLASS32 - /var/lib/gems/1.8/gems/amatch-0.2.5/lib/amatch.so

As the “ELFCLASS32″ bit in the error message suggests, it’s an architecture issue:

$ file /var/lib/gems/1.8/gems/amatch-0.2.5/lib/amatch.so
/var/lib/gems/1.8/gems/amatch-0.2.5/lib/amatch.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped

It can be remedied easily by supplying the target arch like this:

$ ARCHFLAGS="-arch x86_64" gem install amatch