The insider's guide to everything sparqcode
Header image

This problem has been bugging me for quite a while and the usual googling did not get me a solution that worked.

After some experimentation and a bit more research, I found the answer in the comments section of a blog post here: http://aflatter.de/2010/06/testing-headers-and-ssl-with-cucumber-and-capybara/

So let me share the solution I ended up with. First, we have to hack the Capybara Driver and allow the headers to be overridden. This part I just copied verbatim from the blog post. You can put this file anywhere in features/support.

module RackTestMixin

  def self.included(mod)
    mod.class_eval do
      # This is where we save additional entries.
      def hacked_env
        @hacked_env ||= {}
      end

      # Alias the original method for further use.
      alias_method :original_env, :env

      # Override the method to merge additional headers.
      # Plus this implicitly makes it public.
      def env
        original_env.merge(hacked_env)
      end
    end
  end

end

Capybara::Driver::RackTest.send :include, RackTestMixin

module HeadersHackHelper

  def add_headers(headers)
    page.driver.hacked_env.merge!(headers)
  end

end

World(HeadersHackHelper)

Now, we need to add a new step definition. This is where we diverge from the blog post.

Given /^my user agent is "(.+)"$/ do |agent|
  add_headers({'HTTP_USER_AGENT'=> agent})
end

So that’s it for testing user agent strings. Now, I was trying to figure this out because I wanted cucumber to run tests for different mobile phone types. So it made sense for me to throw in another step definition that would make this easier.

Given /^I have an? (.+)$/ do |phone_name|
  add_headers({‘HTTP_USER_AGENT’=> SAMPLE_AGENT_STRING[phone_name]})
end

SAMPLE_AGENT_STRING can be defined as a constant hash like below:

#Sample user agent strings
SAMPLE_AGENT_STRING={
  “iPhone” => “Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7″,
  “Android” => “HTC_Eris Mozilla/5.0 (Linux; U; Android 4.0; en-ca; Build/GINGERBREAD) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1″,
  “Windows Mobile” => “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HTC_Touch_Diamond2_T5353; Windows Phone 6.5)”,
  “Windows Phone 7″ => “Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0) Asus;Galaxy6″,
  “Blackberry” => “BlackBerry9700/5.0.0.351 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/123″,
  “Palm Pre” => “Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0″,
  “Nokia N97″ => “Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124″
}

Now I can write scenarios like:

Given I have an iPhone
And I am viewing “/detect-phone”
Then I should see “You are using an iPhone!”


Several months ago we needed to implement a billing system. Conceptually, recurring payments are simple – ask for a customer’s payment card, save it, and then process it at later dates through a payment gateway.

Implementing it, on the other hand, is tricky, all because of one thorny issue: security. Hosting our site on the EC2 cloud didn’t make PCI compliance matters easier either.

That’s when we found Braintree.

Braintree’s a relatively recent newcomer to the payment game. They’re young, and they’re growing fast. Since 2007, they’ve been picked up by hotshot Web 2.0 companies like 37signals, Github, Disqus.

Now I can’t say it enough: I. Heart. Braintree.

Their secret sauce? Excellent customer service, a clean API, and a little thing they like to call Transparent Redirect.

Here’s how it works.

A standard transaction model usually goes something like this,

  1. User enters credit card information
  2. Credit card information is sent to a secure server hosted by you
  3. Card is processed through the payment gateways’s API.

All the extraneous work is done in securing your own server. To bypass that, the other option is to redirect – albiet jarringly – to a 3rd-party site.

But here’s the cleverness of Braintree’s transparent redirect.

  1. User enters credit card information
  2. Credit card information is sent directly to Braintree’s server, bypassing your servers
  3. Braintree silently redirects to a callback you supply
  4. Your callback handles the credit card through encrypted tokens

The best part is that during this whole process users will never know they’ve left the site. And since you never look at or deal with sensitive information directly, the need to take any extra steps to secure your servers is minimal.

From a code level, here are the steps to process a transaction.

1. Encrypt transaction details

tr_data = Braintree::TransparentRedirect.transaction_data(
                   :redirect_url => "http://example.com/your_callback",
                   :transaction => {
                     :type => "sale",
                     :amount => "10.00"
                    })

2. Construct the form and embed the transaction details

3. Handle the callback

def your_callback
  result = Braintree::TransparentRedirect.confirm(query_string)
  if result.success?
    puts "Hoorah!"
  else
    puts "Oh FUBAR!!"
  end
end

That’s it. Simple eh?

They have APIs written for Ruby, Java, PHP, Phython, and .NET.

Did I also mention their excellent customer service? Check out how fast they reply!

We’ve been spending some time thinking about how to integrate sparqcodes with social media sites (Facebook, Twitter, Yelp, etc) and one of the recurring themes among all of these sites is the use of OAuth for authentication.  From what I understand OAuth was born from the use case of needing to do something on behalf of a user, but not requiring the user to enter sensitive information like her password.

All of the more common ruby gems out there seem to support that use case very well, but what’s been completely neglected is the classic scenario of a website getting an API key and doing something on the provider’s website.  For example: searching for users in on Twitter based on a supplied name.

I fought with the “standard” OAuth ruby gem for about a day on this scenario before giving up.  The documentation was fuzzy, and even though I had supplied all the required data but the gem wasn’t signing URLs properly.  I had almost reached my wits end before it occurred to me that the Twitter Gem must have solved this problem already.  Sure enough, they use a little known gem called Simple OAuth.

With this gem, doing query string based authentication becomes incredibly simple (using Yelp as an example).

params = {
:term => 'Starbucks',
:location => 'Seattle'
}

keys_hash = {
:key => 'consumer key',
:secret => 'consumer secret',
:token => 'token key',
:token_secret => 'token secret'
}

header = SimpleOAuth::Header.new(:get, "http://api.yelp.com/v2/search", params, keys_hash)
response = Typhoeus::Request.get("http://api.yelp.com/v2/search", :params => params.merge(header.signed_params))
render :text => response.body

Rails URL Redirect

Posted by Lee on January 19, 2010 in Technical Development - (0 Comments)
redirect_to :overwrite_params => {:controller=>’survey’, :action=>’handle_single_scan’}

Here’s a little trick I discovered recently.

I wanted to rewrite a url, forwarding a request to another controller, with all the other parameters intact. Rather than define each individual parameter, I found that rails has a built in API to preserve the existing URL with just a few fields specified.

For instance, say I had a request going to http://www.mskynet.com/foo/log?id=123&param=456, and I wanted to redirect to http://www.mskynet.com/bar/do_work?id=123&param=456, I could do the following:

redirect_to :overwrite_params => {:controller=>'bar', :action=>'do_work'}

This syntax would let you overwrite any of the parameters that you want to change and keep everything else the same.

If I just wanted to overwrite the parameter ‘id’ but keep the controller and action, I could do:

 redirect_to :overwrite_params => {:id=>'234'}

Check out the :overwrite_params option here: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649

Actionmailer with BackgroundRb

Posted by Lee on November 25, 2009 in Technical Development - (4 Comments)

We have been working on a mailing service for a while now and we really like what we can do with html emails. Unfortunately, with the plethora of smart phones these days, HTML support is inconsistent. We figured that a good stop-gap solution was to offer both HTML and text versions of an email. Preferably in one package.

And that’s where multipart emails come in.

Suprisingly (or not), this was rather easy to implement in Rails 2.3.

There are two ways of doing this. Implicit and explicit multipart emails. I decided to go with the former.

All I had to do was to make sure the content type is set correctly:

 content_type    "multipart/alternative"

Then, I just had to make sure my template file ends with the right signature “foo.text.plain.erb” and “foo.text.html.erb” for plain text and html emails respectively.

See the multipart email section in the official doc here: http://api.rubyonrails.org/classes/ActionMailer/Base.html

I used a controller to trigger the email and it all worked just like a charm. I had my email with both text and html components. I checked in the code, fired up my mailer service which runs in backgroundrb and called it a day.

That’s when I saw this error popping up:

Message:can’t convert nil into String
/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:551:in `quote’
/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:551:in `read_multipart’
/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:540:in `parse_body_0′
/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:522:in `parse_body’
/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:476:in `body=’
/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/base.rb:650:in `create_mail’
can't convert nil into String

/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:551:in `quote'

/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:551:in `read_multipart'

/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:540:in `parse_body_0'

/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:522:in `parse_body'

/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb:476:in `body='

/usr/lib/ruby/gems/1.8/gems/actionmailer-2.3.2/lib/action_mailer/base.rb:650:in `create_mail'

...

After some investigation, I figure that this is one of those things where backgroundrb is incompatible with a certain feature of rails. I considered fudging around with the tmail code but gave up on that endeavor quickly. Instead, I decided to work around with an explicit version of the multipart email. To my delight, that worked perfectly.


part :content_type => “text/plain”,
  :body => render_message(“foo.text.plain”, :variable1=>variable1, :variable2 => variable2)
part :content_type => “text/html”,
  :body => render_message(“foo.text.html”, :variable1=>variable1, :variable2 => variable2)

Be sure to declare text/plain and text/html in that order. Email clients like Gmail may not offer the text alternative or show the HTML version automatically if you change that order.

The template files work as-is without any modifications. Well, crisis averted. Back to making some barcodes. :)

Mongrel and Snow Leopard

Posted by Lee on November 20, 2009 in Technical Development - (0 Comments)

So the ongoing saga of upgrade woes continues… You would think that “sudo gem update” should take care of upgrading all my old gems in Snow Leopard with all its 64-bit glory…

Nope.

It started when “ruby script/server” started WebBrick instead of Mongrel. That’s odd, but I figure I could work around it by just running “sudo gem install mongrel” again.

Unfortunately, that didn’t do the trick. So I tried summoning Mongrel directly:

mongrel_rails start

and I got this in return:

/Users/.../.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle: dlopen(/Users/.../.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle, 9): no suitable image found.  Did find: (LoadError)

 /Users/.../.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle: no matching architecture in universal wrapper - /Users/.../.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle

 from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'

...

Luckily, Google saves the day and I found this: http://stackoverflow.com/questions/1350486/ruby-on-rails-staring-mongrel-server

I ran the following commands and it all worked as advertised. Phew, that one was easy.

sudo gem uninstall mongrel

sudo gem uninstall fastthread

sudo gem install mongrel
/Users/yowhan/.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle: dlopen(/Users/yowhan/.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle, 9): no suitable image found.  Did find: (LoadError)
/Users/yowhan/.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle: no matching architecture in universal wrapper – /Users/yowhan/.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/http11.bundle
from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require’
from /Users/yowhan/.gem/ruby/1.8/gems/mongrel-1.1.5/bin/../lib/mongrel.rb:12
from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_requir

MySQL, Rails and Snow Leopard

Posted by Lee on November 18, 2009 in Technical Development - (0 Comments)

Ruby on Rails

After much hesitation, I took the dive and upgraded to Snow Leopard today. I ran into some ruby and MySQL errors, but other early adopters in our dev team had already prepared me for that. However, I would soon run into an issue that got me stumped. It turned out that I had forgotten something really simple.

So I had reinstall MySQL 64-bit and updated all my gems, but a particular mysql gem would refuse to reinstall.

There was this helpful document that several devs on my team sent me: http://stackoverflow.com/questions/991708/rails-mysql-and-snow-leopard

Unfortunately, I would get the following error even executing the recommended solution:

yowhan:~ $ sudo env ARCHFLAGS=”-arch x86_64″ gem install -V  mysql — –with-mysql-config=/usr/local/mysql/bin/mysql_config
GET 200 OK: http://gems.rubyforge.org/latest_specs.4.8.gz
GET 200 OK: http://gems.github.com/latest_specs.4.8.gz
GET 200 OK: http://gems.rubyforge.org/quick/Marshal.4.8/mysql-2.8.1.gemspec.rz
Installing gem mysql-2.8.1
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/COPYING
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/COPYING.ja
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/History.txt
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/Manifest.txt
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/README.txt
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/Rakefile
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/ext/mysql_api/extconf.rb
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/ext/mysql_api/mysql.c
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/extra/README.html
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/extra/README_ja.html
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/extra/tommy.css
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/lib/mysql.rb
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/tasks/gem.rake
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/tasks/native.rake
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/tasks/vendor_mysql.rake
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/test/test_mysql.rb
Building native extensions.  This could take a while…
ERROR:  Error installing mysql:
ERROR: Failed to build gem native extension.
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb
checking for mysql_query() in -lmysqlclient… no
checking for main() in -lm… yes
checking for mysql_query() in -lmysqlclient… no
checking for main() in -lz… yes
checking for mysql_query() in -lmysqlclient… no
checking for main() in -lsocket… no
checking for mysql_query() in -lmysqlclient… no
checking for main() in -lnsl… no
checking for mysql_query() in -lmysqlclient… no
checking for main() in -lmygcc… no
checking for mysql_query() in -lmysqlclient… no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.
Provided configuration options:
–with-opt-dir
–without-opt-dir
–with-opt-include
–without-opt-include=${opt-dir}/include
–with-opt-lib
–without-opt-lib=${opt-dir}/lib
–with-make-prog
–without-make-prog
–srcdir=.
–curdir
–ruby=/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
–with-mysql-config
–without-mysql-config
–with-mysql-dir
–without-mysql-dir
–with-mysql-include
–without-mysql-include=${mysql-dir}/include
–with-mysql-lib
–without-mysql-lib=${mysql-dir}/lib
–with-mysqlclientlib
–without-mysqlclientlib
–with-mlib
–without-mlib
–with-mysqlclientlib
–without-mysqlclientlib
–with-zlib
–without-zlib
–with-mysqlclientlib
–without-mysqlclientlib
–with-socketlib
–without-socketlib
–with-mysqlclientlib
–without-mysqlclientlib
–with-nsllib
–without-nsllib
–with-mysqlclientlib
–without-mysqlclientlib
–with-mygcclib
–without-mygcclib
–with-mysqlclientlib
–without-mysqlclientlib
Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/mysql-2.8.1 for inspection.

Results logged to /Library/Ruby/Gems/1.8/gems/mysql-2.8.1/ext/mysql_api/gem_make.out

sudo env ARCHFLAGS="-arch x86_64" gem install -V  mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

GET 200 OK: http://gems.rubyforge.org/latest_specs.4.8.gz

GET 200 OK: http://gems.github.com/latest_specs.4.8.gz

GET 200 OK: http://gems.rubyforge.org/quick/Marshal.4.8/mysql-2.8.1.gemspec.rz

Installing gem mysql-2.8.1

...

/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/test/test_mysql.rb

Building native extensions.  This could take a while...

ERROR:  Error installing mysql:

 ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb

...

*** extconf.rb failed ***

Could not create Makefile due to some reason, probably lack of

necessary libraries and/or headers.  Check the mkmf.log file for more

details.  You may need configuration options.

...

Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/mysql-2.8.1 for inspection.

Results logged to /Library/Ruby/Gems/1.8/gems/mysql-2.8.1/ext/mysql_api/gem_make.out

After several frustrating moments of poking around, a helpful fellow developer pointed out that “mysql” was not in my path. Duh!

I guess I just committed a newbie linux mistake. A quick update to .profile to include “/usr/local/mysql/bin” later, and the above command works perfectly now!

Here’s what I added to my .profile:

#Add mysql to path

export PATH=/usr/local/mysql/bin:$PATH

Hopefully that’s the last of my upgrade issues. :)