Rails 2.3 Nested Object Forms: I’m not Crazy about Them

February 24th, 2009 by

I’m a couple of weeks late, but I just finished reviewing Rails 2.3 Nested Object Forms. While a very nice and “magical” feature, I’ve got to admit that I’m really not that crazy about how it works.

Let me be the first to admit that there’s no one right way to do things. In fact, I’m writing this post particularly because I have a few objections to how this functionality is ultimately exposed, and I’d like to hear arguments from those who disagree. In other words, let me acknowledge the possibility that I am the misguided one.

Read the rest of this entry »

TATFT: Test Private Methods in C++

February 16th, 2009 by

It’s very rare that I do any C++ programming these days. However, one of my oldest customers continues to utilize a C++-based optimization/statistics framework that we helped them build many years ago. The project has a wonderful purpose, and we owe quite a bit to some of the first people to trust us (thank you Sommer and Dorry!).

As a Ruby programmer, I’ve come to love test-driven programming. As such, I’ve made an effort recently to build a test-based workflow into this existing codebase (not always the easiest thing to do, applying a test-base to a large existing codebase). Today I found myself in dire need of being able to test private functions in C++. As a testament to the poor state of testing in other programming languages, many message boards/threads simply told me that I was testing the wrong thing (you should test the public API, not the private implementation). Well, needless to say, this left me a bit uncomfortable. The fact is, the majority of my code is tucked into private methods, and I’d be left with huge long-running end-to-end tests if I strictly followed this heuristic.

However, I came across one golden nugget, one of the most clever hacks I’ve seen in some time. By utilizing pre-processor directives, we can temporarily override the meaning of private and protected in C++ code, essentially aliasing it to public.

 #define protected public
 #define private   public
 #include "TheClassHeaderUnderTest.h"
 #undef protected
 #undef private

See what this is doing? We wrap the class that we’ll be testing in pre-processor directives to interpret protected and private as an alias for public, essentially loading that class (when including the header file) as entirely public. This allows me to access everything! Private methods, private variables, you name it. And now, just like in Ruby, it’s no holds barred, allowing me to poke and prod my objects without being wrapped on the wrist by the compiler.

Even better, these directives simply wrap your includes in your test files. In other words, I don’t have to change my implementation to achieve this.

A clever hack, no matter the language or technology, is a clever hack. And I absolutely love this hack.

Credit: I discovered this technique as a comment on this wiki.

AASM + interning empty string error

February 13th, 2009 by

Second time I’ve run into this in the past week, so I thought I’d share it with you guys. I fumbled for a short while with the extremely unhelpful error message “interning empty string error” after a re-deployment to my staging server. It seemed to be affecting all of my pages, and I couldn’t really load any page.

The Problem

This blog post is valid for rails 2.1.2 and rubyist-aasm 2.0.5. It may apply to other version combinations, but I make no guarantees.

First, let’s dive into the error itself. This error message occurs when you call to_sym on an empty string:

john-mbp:trunk john$ irb
>> "".to_sym
ArgumentError: interning empty string
	from (irb):1:in `to_sym'
	from (irb):1

Now that we know what’s up, let’s dig into my stack trace.

/opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rubyist-aasm-2.0.5/lib/persistence/active_record_persistence.rb:233:in `to_sym’
/opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rubyist-aasm-2.0.5/lib/persistence/active_record_persistence.rb:233:in `aasm_read_state’
/opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rubyist-aasm-2.0.5/lib/persistence/active_record_persistence.rb:135:in `aasm_current_state’
/opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rubyist-aasm-2.0.5/lib/aasm.rb:50:in `disabled?’
/var/vhosts/discovered/releases/20090213213806/app/helpers/base_admin_helper.rb:4:in `disable_link’
/var/vhosts/discovered/releases/20090213213806/app/views/schools/index.rhtml:16:in `_run_erb_47app47views47schools47index46rhtml’
/var/vhosts/discovered/releases/20090213213806/app/views/schools/index.rhtml:12:in `each’
/var/vhosts/discovered/releases/20090213213806/app/views/schools/index.rhtml:12:in `_run_erb_47app47views47schools47index46rhtml’


The cause of this bug is the fact that my newest build added an aasm_state column to the School model, but my migration did not properly default schools to a particular state. As such, when an instance of the model was asked for its state, the AASM codebase raised an error. And this occurred on every page because I was rendering a link to a school in a common layout.

The Solution

After the fact, in SQL:

UPDATE schools SET aasm_state = 'active';

Or better yet, before the fact, in my migration:

def self.up
  add_column :schools, :aasm_state, :string
  School.reset_column_information
  School.update_all("aasm_state", "active")
end

The Lesson

Don’t forget that there’s a difference between a migration for a yet-to-be-deployed application and a live running application. Live apps require you to take into account that data already exists.

Properly Setting HTTP_REFERER in a Rails Integration Test for a File Upload

February 3rd, 2009 by

This one had me frustrated for the past hour. I’ve been writing integration tests for a Rails project and got stuck on an error when I was trying to test that a file upload worked successfully and asserted a redirection was occuring correctly, but ran into the following error:

Expected response to be a <:redirect>, but was <500>
<"No HTTP_REFERER was set in the request to this action, so
redirect_to :back could not be called successfully. If this
is a test, make sure to specify
request.env[\"HTTP_REFERER\"].">

What a lovely error message to send me on a goose chase trying to set HTTP_REFERER directly on the @request as instructed.

Did Not Work

@request.env["HTTP_REFERER"] = '/'
post upload_path, { :file => fixture_file_upload("worddoc.docx", "application/msword") },
  { :html => {:multipart => true} }
assert_redirected_to '/', 'index'

This continued to spit out the same error. I finally stumbled across a post back from 2006 that held the answer. The HTTP_REFERER is not set the same way in an integration test:

Success!

post upload_path, { :file => fixture_file_upload("worddoc.docx", "application/msword") },
  { :html => {:multipart => true}, :referer => '/' }
assert_redirected_to '/', 'index'

Hope that saves anyone else some time if you encounter this error.