Amazon Reduces S3/EC2/Data transfer prices

Amazon announced today some modifications to their pricing tiers.

If you’re a power user of S3, you’ll be glad to know that multi-petabyte ( > 1 million Gigs) users costs have been reduced by more than 15%.

There’s also some good news for users at any level:

Data Transfer into AWS will be free of charge from now through June 30, 2010, making it even easier for customers to get their data into AWS. This applies to data transfer into Amazon EC2, Amazon S3, Amazon SimpleDB, Amazon Relational Database Service, Amazon Simple Queue Service, and Amazon Virtual Private Cloud. Other applicable charges for use of these services continue to apply.

Some additional price reductions apply to EU S3 and EC2, you can check out the complete newsletter here:

Happy uploading / cloud computing.

RAILS_ENV set to “test” in development

I came across this rather annoying detail early on in one of our projects.

Loading development environment (Rails 2.3.4)
=> "development"
=> "development"
>> require 'spec/rails'
=> []
=> "test"
=> "development"
>> exit

Turns out that just by requiring ‘spec/rails’ it was blindly setting the RAILS_ENV constant to ‘test’ without warning. It sorta makes sense, as you would only really need the rspec gem when running tests, but I like to use the standard:

config.gem 'rspec',         :lib => 'spec',         :version => '1.2.9'
config.gem 'rspec-rails', :lib => 'spec/rails', :version => '1.2.9'

so that when new devs come into the project, they know exactly what gems and what versions are required.

This is fine, but saying config.gem actually goes out and requires the rspec gem right then. Obviously this isn’t needed on production, so we can go ahead and do something like

# list gems here that only need to be around for development
if RAILS_ENV == 'development'
  config.gem 'rspec',                   :lib => 'spec',           :version => '1.2.9'
  config.gem 'rspec-rails',             :lib => 'spec/rails',     :version => '1.2.9'

But that still doesn’t solve my issue. So the hunt is on… I started looking in ‘spec/rails’

Then narrowed it down within that file to:
require ‘spec/rails/extensions’

Then from that file to:
require ‘spec/rails/extensions/spec/runner/configuration’

Then from that file to:
require ‘test_help’

Which lives in Rails, (railties/lib/test_help.rb) and performs this brilliant idea:

# Make double-sure the RAILS_ENV is set to test,
# so fixtures are loaded to the right database
silence_warnings { RAILS_ENV = "test" }

As long as you make sure you have

ENV["RAILS_ENV"] ||= 'test'

in your spec_helper.rb, you shouldn’t have any issue with the environment. So I decided to fight fire with fire, and ended up just sticking this into my config/initializers/

# NOTE: this is here because using 
# config.gem 'rspec',              :lib => 'spec',        :version => '1.2.9'
# config.gem 'rspec-rails',        :lib => 'spec/rails',  :version => '1.2.9'
# automatically sets the RAILS_ENV to 'test' no matter what ENV['RAILS_ENV'] is
# see vendor/rails/railties/lib/test_help.rb:3
# so we fire back our own silent hack. pew pew pew. -danny (2009.10.29)

silence_warnings { RAILS_ENV = ENV['RAILS_ENV'] || 'development' }

And just like magic, my development environment is back to RAILS_ENV == ‘development’

Can’t add git remote branch

I love git, but it’s full of gotchas. Here’s one I ran into recently when trying to create a remote branch to do some major code refactoring.

20:22:03>git push origin origin:refs/heads/new_remote_branch
error: src refspec origin does not match any.
fatal: The remote end hung up unexpectedly
error: failed to push some refs to '<repo here>'

Hmm. This has always worked for me before, what gives?

When I took a look at my remote branches:

20:35:33>git branch -r

I noticed that there’s no HEAD pointer. I’m actually not certain of how that came about, but let’s add it:

git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/master

Now this looks a little better:

20:38:10>git branch -r
  origin/HEAD -> origin/master

And now git knows what do do when you try to branch off origin to a new remote branch:

20:41:14 >git push origin origin:refs/heads/new_remote_branch
Counting objects: 429, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (257/257), done.
Writing objects: 100% (370/370), 54.03 KiB, done.
Total 370 (delta 247), reused 167 (delta 110)
To git@<repo_url_here>.git
 * [new branch]      origin/HEAD -> new_remote_branch

Great. Add it to your evernote and move on with your life 😀

How to remove trailing slashes to get better analytics on your page views

I noticed when viewing my google analytics report that I had several duplicate entries for the same that looked like /page, and then /page/ (a trailing slash).

Obviously I’d like these two to be combined to get one statistic for those page views. There are a couple of ways to do this.

1) The particular project in question is using nginx. We can use a rewrite to get rid of the slash.

server {


    rewrite ^/(.*)/$ /$1 permanent;

    location / {

2) You can also get creative with a little rack fun.

sudo gem install rack-rewrite

# then slip the following in your environment.rb

config.gem 'rack-rewrite', '~> 0.1.2'

require 'rack-rewrite'
config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
  r301 %r{^/(.*)/$}, '/$1'

3) Other ways? Leave me some feedback.

Now you should start to see only /page hits in your google analytics and no more /page/


Internet Explorer APPLET tag missing CODE parameter

Internet Explorer integration is by far my least favorite part of developing web applications. I had this nice little java applet that was working fine in Firefox, Chrome, Safari, Opera, etc. (basically WebKit and Mozilla browsers) but would annoyingly sit and seemingly load forever when viewed through Internet Explorer (7).

I was loading the applet with some standard javascript:

var _info = navigator.userAgent;
var _ns = false;
var _ns6 = false;
var _ie = (_info.indexOf("MSIE") > 0 && _info.indexOf("Win") > 0 && _info.indexOf("Windows 3.1") < 0);
if (_info.indexOf("Opera") > 0) _ie = false;
var _ns = (navigator.appName.indexOf("Netscape") >= 0 && ((_info.indexOf("Win") > 0 && _info.indexOf("Win16") < 0) || (_info.indexOf("Sun") > 0) || (_info.indexOf("Linux") > 0) || (_info.indexOf("AIX") > 0) || (_info.indexOf("OS/2") > 0) || (_info.indexOf("IRIX") > 0)));
var _ns6 = ((_ns == true) && (_info.indexOf("Mozilla/5") >= 0));
if (_ie == true) {
  document.writeln('<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH="250" HEIGHT="250" NAME="myapplet" codebase=",4,0,0">');
else if (_ns == true && _ns6 == false) { 
  // BEGIN: Update parameters below for NETSCAPE 3.x and 4.x support.
  document.write('<EMBED ');
  document.write('type="application/x-java-applet;version=1.4" ');
  document.write('CODE="MyApplet.class" ');
  document.write('JAVA_CODEBASE="./" ');
  document.write('ARCHIVE="lib/somejar.jar" ');
  document.write('NAME="myapplet" ');
  document.write('WIDTH="250" ');
  document.write('HEIGHT="250" ');
  document.write('url="http://localhost:8080/upload/process.jsp" ');
  document.write('paramfile="uploadfile" ');
  document.write('param1="todo" ');
  document.write('value1="upload" ');
  document.write('folderdepth="-1" ');
  document.write('param3="relativefilename" ');
  document.write('value3="true" ');
  document.write('mode="http" ');
  document.write('scriptable=true ');
  // END
else {
  document.writeln('<APPLET CODE="MyApplet.class" JAVA_CODEBASE="./" ARCHIVE="lib/somejar.jar" WIDTH="250" HEIGHT="250" NAME="fileupload">');
// BEGIN: Update parameters below for INTERNET EXPLORER, FIREFOX, SAFARI, OPERA, MOZILLA, NETSCAPE 6+ support.
document.writeln('<PARAM NAME=CODE VALUE="MyApplet.class">');
document.writeln('<PARAM NAME=CODEBASE VALUE="./">');
document.writeln('<PARAM NAME=ARCHIVE VALUE="lib/somejar.jar">');
document.writeln('<PARAM NAME=NAME VALUE="myapplet">');
document.writeln('<PARAM NAME="type" VALUE="application/x-java-applet;version=1.4">');
document.writeln('<PARAM NAME="scriptable" VALUE="true">');
document.writeln('<PARAM NAME="url" VALUE="http://localhost:8080/upload/process.jsp">');
document.writeln('<PARAM NAME="paramfile" VALUE="uploadfile">');
document.writeln('<PARAM NAME="param1" VALUE="todo">');
document.writeln('<PARAM NAME="value1" VALUE="upload">');
document.writeln('<PARAM NAME="folderdepth" VALUE="-1">');
document.writeln('<PARAM NAME="param3" VALUE="relativefilename">');
document.writeln('<PARAM NAME="value3" VALUE="true">');
document.writeln('<PARAM NAME="mode" VALUE="http">');
// END
if (_ie == true) {
else if (_ns == true && _ns6 == false) {
else {

Taking a look at the java console output, all I see is “APPLET tag missing CODE parameter”… not very helpful, as I clearly should be writing the

<param name="CODE" value="MyApplet.class" />

to the page just fine.

Solution after the jump =>

As it turns out, this happens to be a jQuery related issue. And while I’m not sure of the exact reason for it, I suspect it has to do with how it fires events after the document is done loading. The applet loads when I take out jQuery, and dies when I add it back in.

My workaround was simply to write the html tags into a js variable, and then stick it into an empty div after the document was ready using jQuery’s $(document).ready() function:

<div id="applet"></div>

var _info = navigator.userAgent;
var _ns = false;
var _ns6 = false;
var _ie = (_info.indexOf("MSIE") > 0 && _info.indexOf("Win") > 0 && _info.indexOf("Windows 3.1") < 0);
if (_info.indexOf("Opera") > 0) _ie = false;
var _ns = (navigator.appName.indexOf("Netscape") >= 0 && ((_info.indexOf("Win") > 0 && _info.indexOf("Win16") < 0) || (_info.indexOf("Sun") > 0) || (_info.indexOf("Linux") > 0) || (_info.indexOf("AIX") > 0) || (_info.indexOf("OS/2") > 0) || (_info.indexOf("IRIX") > 0)));
var _ns6 = ((_ns == true) && (_info.indexOf("Mozilla/5") >= 0));

var uploader = "";

if (_ie == true) {
  uploader += '<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH="250" HEIGHT="250" NAME="myapplet" codebase=",4,0,0">';
else if (_ns == true && _ns6 == false) { 
  // BEGIN: Update parameters below for NETSCAPE 3.x and 4.x support.
  uploader += '<EMBED ';
  uploader += 'type="application/x-java-applet;version=1.4" ';
  uploader += 'CODE="MyApplet.class" ';
  uploader += 'JAVA_CODEBASE="./" ';
  uploader += 'ARCHIVE="lib/somejar.jar" ';
  uploader += 'NAME="myapplet" ';
  uploader += 'WIDTH="250" ';
  uploader += 'HEIGHT="250" ';
  uploader += 'url="http://localhost:8080/upload/process.jsp" ';
  uploader += 'paramfile="uploadfile" ';
  uploader += 'param1="todo" ';
  uploader += 'value1="upload" ';
  uploader += 'folderdepth="-1" ';
  uploader += 'param3="relativefilename" ';
  uploader += 'value3="true" ';
  uploader += 'mode="http" ';
  uploader += 'scriptable=true ';
  uploader += 'pluginspage=""><NOEMBED>';
  // END
else {
  uploader += '<APPLET CODE="MyApplet.class" JAVA_CODEBASE="./" ARCHIVE="lib/somejar.jar" WIDTH="250" HEIGHT="250" NAME="fileupload">';
// BEGIN: Update parameters below for INTERNET EXPLORER, FIREFOX, SAFARI, OPERA, MOZILLA, NETSCAPE 6+ support.
uploader += '<PARAM NAME=CODE VALUE="MyApplet.class">';
uploader += '<PARAM NAME=CODEBASE VALUE="./">';
uploader += '<PARAM NAME=ARCHIVE VALUE="lib/somejar.jar">';
uploader += '<PARAM NAME=NAME VALUE="myapplet">';
uploader += '<PARAM NAME="type" VALUE="application/x-java-applet;version=1.4">';
uploader += '<PARAM NAME="scriptable" VALUE="true">';
uploader += '<PARAM NAME="url" VALUE="http://localhost:8080/upload/process.jsp">';
uploader += '<PARAM NAME="paramfile" VALUE="uploadfile">';
uploader += '<PARAM NAME="param1" VALUE="todo">';
uploader += '<PARAM NAME="value1" VALUE="upload">';
uploader += '<PARAM NAME="folderdepth" VALUE="-1">';
uploader += '<PARAM NAME="param3" VALUE="relativefilename">';
uploader += '<PARAM NAME="value3" VALUE="true">';
uploader += '<PARAM NAME="mode" VALUE="http">';
// END
if (_ie == true) {
  uploader += '</OBJECT>';
else if (_ns == true && _ns6 == false) {
  uploader += '</NOEMBED></EMBED>';
else {
  uploader += '</APPLET>';

$(document).ready(function() {

And low and behold, it loads right up in Internet Explorer now. Hope this saves some of you some time.

[ActionMailer] Multipart emails with attachments

Ran into a gotcha the other day that I thought was worth a note. I had a multipart email template that was sending invoice receipts in both plain text and html format. This was all working fine by just defining the views as order_placed.text.plain.erb and order_placed.text.html.erb, ActionMailer took care of the nitty gritty.

However, when I wanted to add a pdf attachment along with the email with the standard:

attachment :content_type => "application/pdf", :body => file, :filename => "file.pdf"

my emails starting coming through with only the attachment, no text.

After some light research, I discovered that

Once you use the attachment method, ActionMailer will no longer automagically use the correct template based on the filename, nor will it properly order the alternative parts. You must declare which template you are using for each content type via the part method. And you must declare these templates in the proper order.

Love, Rails

Turns out the proper way to mash all of these different mimetypes together is something like the following:

  def order_placed(purchase)
    subject "Your #{APP_NAME} receipt"
    content_type "multipart/mixed"
    part :content_type => "multipart/alternative" do |a|
      a.part "text/plain" do |p|
        p.body = render_message 'order_placed.text.plain.erb', :purchase => purchase

      a.part "text/html" do |p|
        p.body = render_message 'order_placed.text.html.erb', :purchase => purchase
    attachment :content_type => "application/pdf", :body => the_pdf_file, :filename => "some_filename.pdf"

And just like magic, my emails are coming through fine, attachment and all. Hope this saves somebody a headache.

Merging Hash and HashWithIndifferentAccess

Ran into a gotcha the other day I thought I’d share. It came about in some code that was trying to give some default values in a hash, then merge in some params before creating an object. It looked something like this:{:is_cool => true}.merge(params[:thing])

The gotcha here is that params is a HashWithIndifferentAccess, but {:is_cool => true} is not. Merging these two will actually drop the return value to just Hash. Observe.

   >> params = => {:is_cool => false, :name => 'Cool Thing'})
   => {"thing"=>{"name"=>"Cool Thing", "is_cool"=>false}}
   >> params.class
   => HashWithIndifferentAccess
   >> ({:is_class => true}.merge(params[:thing])).class
   => Hash

When you look at what is created when merging the two, you notice that there are actually two separate keys of the same name, one a symbol, one a string.

    >> {:is_cool => true}.merge(params[:thing])
    => {"name"=>"Cool Thing", :is_cool=>true, "is_cool"=>false}

And then when you pass this hash to your ActiveRecord model, you can see that it favors the symbol.

   >> thing ={:is_cool => true}.merge(params[:thing]))
   => #<Thing id: nil, name: "Cool Thing", is_cool: true, created_at: nil, updated_at: nil>

The solution is to either use a string as your key:

   >> thing ={'is_cool' => true}.merge(params[:thing]))
   => #<Thing id: nil, name: "Cool Thing", is_cool: false, created_at: nil, updated_at: nil>

Or make the initial hash a HashWithIndifferentAccess:

   >> thing = => true).merge(params[:thing]))
   => #<Thing id: nil, name: "Cool Thing", is_cool: false, created_at: nil, updated_at: nil>

So yea, keep an eye out for this gremlin.

Multi-part emails sent from a cron job delivered as text/plain only

Had an interesting problem today. We use multipart emails in our client project snapizzi so users can get pretty little emails if their client supports html. However, we found that any email sent from a cron task was being sent with a mime-type of text/plain, but rendering only the html text. Fugly.

Turns out this is an active ticket in rails which can be found here, with a patch to fix it that can be found here.

We use Rails as a git submodule, so rather than applying the patch and freezing, I just added an actionmailer_fix.rb to my initializers. At least until this patch makes it into Rails.