Swishstache

Octopressed yet?

Another Way to Check Controller Response Status

If you have examples that exercise a controller, you’re probably testing the response status often.

The easiest way to do this is:

response.code.should == '200'

If you include “ActionController::StatusCodes” in your spec, you can do something like this:

include ActionController::StatusCodes

    it "returns a status of OK"
      response.status.should == interpret_status(:ok)
    end

Maybe it saves you that split second of translating http response codes in your head.

Edge Cases for the Aws-s3 Gem

Anytime I have a project that requires accessing an S3 bucket, my go-to gem has always been Marcel Molina’s aws-s3.

A few rough spots have bubbled up recently and I thought I’d post my solutions in case they’re troubling others.

One-off connections

When you call “.establish_connection!” on AWS::S3::Base, AWS::S3::Object, or AWS::S3::Bucket, the connection details are persisted across all request methods on those classes. This means that if you change the connection in (for example) an admin controller using AWS::S3::S3Object.establish_connection! and then another controller attempts to use AWS::S3::S3Object.store (but expects a different connection), you’ve just had an object posted to the wrong place.

The example code below creates a one-time-use connection and then stores a text file.

file_name = 'file.txt'
local_file_path = "/path/to/#{file_name}"
key = "/bucket_name/#{file_name}"
connection = AWS::S3::Connection.connect(:access_key_id => <your_access_key_id>, :secret_access_key => <your_secret_access_key>)
connection.request(:put, key, {"x-amz-acl" => "public-read"}, open(local_file_path))

Setting response headers

I had a need to store a file and set response headers such that accessing the files’ url would prompt a download in the browser. Amazon allows you to set a handful of response headers (see documentation). Storing the file was done via the aws-s3 gem so sending the response headers at that time wasn’t possible. Instead, I created a method that returned a signed request with the desired response headers specified in the request url.

The example code below builds a signed request with response headers that would cause a download prompt in a browser. Note that this is assuming use of the default connection by referencing “AWS::S3::Base.connection”.

file_name = 'file.csv'
file_path = "/bucket_name/#{file_name}"

s3_connection = AWS::S3::Base.connection
request = Net::HTTP::Get.new(file_path, {})
expiry = Time.now.to_i + 300
response_headers = "response-content-disposition=attachment;filename=#{file_name}"
string_to_sign = AWS::S3::Authentication::CanonicalString.new(request, :expires => expiry) + "?#{response_headers}"

digest = OpenSSL::Digest::Digest.new('sha1')
b64_hmac = [OpenSSL::HMAC.digest(digest, s3_connection.secret_access_key, string_to_sign)].pack("m").strip
signature = CGI.escape(b64_hmac)

"https://s3.amazonaws.com#{file_path}?AWSAccessKeyId=#{s3_connection.access_key_id}&Expires=#{expiry}&Signature=#{signature}&#{response_headers}"

Just How Does OS X Set a UTI?

(from my old Posterous Blog)

Apparently, if you change the file extension (in 10.7 at least), the UTI also changes (to a generic like “public.data”). OS X must synthesize the UTI from the file extension.

Grah! That means it’s possible to miss actual image files on my computer using spotlight if they have no file extension or a goofed one like “jepg”.

A search for “kMDItemContentType == ‘public.data’” yields about 9,800 files – all without extensions.

GRASH! It. Because Your Memory Is for Finding Car Keys.

UPDATED: @jo_liss brought “ctrl + R” to my attention (hit esc to cancel).

(from my old Posterous Blog)

I have a poor memory coupled with laziness. As such, I often find myself too lazy to lookup a command. Often still, I know I’ve done it before. I could mash my up arrow key until I found it or I could GRASH it.

“Grash”? What. In. The. Hell. You say? We’ll it’s just a simple function for your shell that greps your .bash_history for a string you feed it.

Example Usage

How do I start my local redis server again?

$ grash 'redis'
$ redis-server /usr/local/etc/redis.conf
$ redis-server /usr/local/etc/redis.conf

Ah! I’ve done it twice before.

How You Can Get It

Just drop these lines in your bash profile (~/.bash_profile or ~/.profile) and reload your shell session.