Matt Hodan http://blog.matthodan.com Tech news, code samples, product reviews, etc. posterous.com Fri, 23 Dec 2011 11:25:00 -0800 Bookmarklet Loader in CoffeeScript http://blog.matthodan.com/bookmarklet-loader-in-coffeescript http://blog.matthodan.com/bookmarklet-loader-in-coffeescript

Bookmarklet Loader is a template bookmarklet that injects your app’s .js and .css into the current page when clicked. You can grab the code on GitHub:

Bookmarklet Loader

Bookmarklet Loader is written in CoffeeScript, however bookmarklets must be JavaScript and URL encoded. CoffeeMarklet does a great job of converting CoffeeScript to bookmarklet-friendly JavaScript. I recommend you use it to generate your bookmarklet once you’ve configured Bookmarklet Loader.

Happy Holidays!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Mon, 10 Oct 2011 11:52:02 -0700 How to test [something] with Rspec http://blog.matthodan.com/how-to-test-something-with-rspec http://blog.matthodan.com/how-to-test-something-with-rspec

I’ve slowly been learning how to test my Rails projects with Rspec and I thought it would be helpful to document this experience. I’m sure there are better, faster, smarter ways to test these concepts, so please do tell me in a comment so I (and others) can learn!

To get started, make sure you have Rspec installed properly. Ryan Bates created a great Railscast that walks through setting up Rspec.

I’m going to add to this post as I create tests over the coming weeks/months. Please be patient, and don’t forget to comment if you see something that could be done better, faster, smarter!

Understanding Rspec Organization

One of my favorite features of Rspec is that it helps you easily organize your tests. Here is an example of how a simple set of tests might be organized:

describe SourcesController do
  describe "#index" do
    before :each do
      @request.env['HTTP_AUTHORIZATION'] = "Basic #{ActiveSupport::Base64::encode64('user:secret')}"
    end

    it "should have this action" do
      get :index
      response.should be_success
    end

    it "should require auth to access" do
      @request.env['HTTP_AUTHORIZATION'] = nil
      get :index
      response.status.should == 401
    end
  end
end

Rspec gives us the keyword “describe” so we can group related tests. In the above example, I’m testing the index action of the SourcesController. If I wanted to add a new action, I might create a new “describe” block called “#new”. There are no formal organization rules here (as far as I can tell), this is just my NooB convention. Post a comment if you have a best practice that I should be using!

Rspec Expectations and Matchers

In Rspec, there are a couple of concepts that will get you 80% of the way to where you need to be, then there are about a hundred concepts that get you the final 20%. To get 80%, you should start with:

object.should
object.should_not

Rspec’s Spec::Expectations module adds the “#should” and “#should_not” methods to Ruby’s Object class. These methods are the key to how Rspec works. Every object in your tests will now have these two expectation methods, which you can use to verify a value.

With #should and #should_not in our arsenal, we can go a step further and start to think about matchers. The following is a list of positive matchers. Most also have a negative equivalent (i.e. “not_equal”, “not_be_close”, etc.). You can use these matchers to make Rspec code read like a novel, which is one of the things I LOVE about Rspec.

object.should equal [value]
object.should be_close [value], [tolerance]
object.should be [value]
object.should be_between([value-x], [value-y])
object.should predicate [optional args]
object.should match [regex]
object.should be_an_instance_of [class]
object.should be_a_kind_of [class]
object.should respond_to [symbol|string]
object.should include [object]
object.should have([number]).things
object.should have_at_most([number]).things
object.should have([number]).errors_on([symbol])

To test for exceptions and changes:

lambda {[do something]}.should raise_error
lambda {[do something]}.should raise_error([exception] [, optional message])
lambda {[do something]}.should change([instance], [method]).from([x]).to([y])
expect {[do something]}.to change([instance], [method_as_symbol]).from([x]).to([y])

Testing Models

All of the tests for your models reside in the “spec/models” folder, which the Rails generator creates when you create a new model. In here, you should see a file named “[yourmodel]_spec.rb” for each model you’ve created with a Rails generator since installing Rspec.

A good rule of thumb for testing models is that you should have at least one test for every property of your model. You should also test things like validations, accessibility, and filters. But, you should only test your code (i.e. don’t test ActiveRecord, it’s already well tested).

To be continued…

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Sun, 28 Aug 2011 00:03:00 -0700 Endless Scroll (a.k.a. Endless Page) with jQuery http://blog.matthodan.com/endless-scroll-aka-endless-page-and-pageless http://blog.matthodan.com/endless-scroll-aka-endless-page-and-pageless

I decided to write a super lightweight endless scroll (a.k.a. endless page, pageless, without pagination, etc.) plugin for jQuery. It will let me trigger some code whenever the user scrolls within a certain number of pixels from the bottom of the page.

I’ll get right to the juicy details. Here is the plugin code, and yes, it’s written in CoffeeScript. If you need javascript, feel free to copy and paste this code into the CoffeeScript parser at http://jashkenas.github.com/coffee-script/.

(($) ->
  $.fn.nearBottom = (options) ->
    defaults = {
      pixelsFromBottom: 100,
      delay: 250,
      callback: -> false
    }
    options = $.extend defaults, options

    do checkScrollPosition = ->
      documentHeight = $(document).height()
      scrollHeight = $(document).scrollTop()
      windowHeight = $(window).height()
      pixelsToBottom = documentHeight - scrollHeight - windowHeight

      scrollable = ->
        documentHeight > windowHeight

      nearBottom = ->
        pixelsToBottom <= options.pixelsFromBottom

      enqueueNextCheck = (delay) ->
        setTimeout checkScrollPosition, delay

      if scrollable() && nearBottom()
        if options.callback() == true
          enqueueNextCheck(options.delay)
      else
        enqueueNextCheck(options.delay)
)(jQuery)

After adding this plugin to your project, you can use it by calling nearBottom on a jQuery object.

yourFunction = ->
  alert "We're near the bottom of the page!"
  true

$(this).nearBottom {
  callback: yourFunction,
  delay: 500,
  pixelsFromBottom: 100
}

I’ve included all of the optional settings above.

  • callback is the function to execute when the user scrolls close to the bottom of the page. This function must return a value of true for the plugin to continue to check the user’s scroll position. In other words, if you want to stop the plugin, return false and your callback will not be called again.
  • delay is how many milliseconds to wait between each check of the scroll position
  • pixelsFromBottom is the distance from the bottom of the page that triggers the callback.

    I’ll add this to GitHub soon!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Sat, 30 Jul 2011 12:43:00 -0700 Using Masked Identifiers to Reference ActiveRecord Models http://blog.matthodan.com/63159496 http://blog.matthodan.com/63159496

Just about every time I start a new Rails project, I find myself building out a way to reference records based on a masked identifier. It just feels wrong to me to display the count of the number of records in the database, which is the Rails default.

UPDATE: I created a Rails plugin that makes it easy to add a non-incrementing masked identifier to any ActiveRecord object. Check out the Github page for more info:

http://github.com/matthodan/masked-identifier

To solve this problem, I built a couple libraries that a) generate a guaranteed-to-be-unique code to use for a masked identifier and b) automatically add the masked identifier code to new records when they are saved for the first time.

Here is the code for the code generator:

# CodeGenerator creates unique codes based on a column of an ActiveRecord object
#
# Usage:
# 1) Copy this file into your [rails project]/lib directory
# /lib/code_generator.rb
#
# 2) Add an initializer to your Rails project
# require 'code_generator'
#
# 3) Generate a unique code based on an ActiveRecord model
# CodeGenerator.unique_code(YourModel, 'name_of_unique_column', length_of_code)

class CodeGenerator
  def self.unique_code(klass, field, size)
    code = self.random_code(size)
    until self.code_is_unique?(klass, field, code)
      code = self.random_code(size)
    end
    return code
  end

  private
  def self.code_is_unique?(klass, field, code)
    return true if klass.class.send('find_by_' + field, code).nil?
  end

  def self.random_code(size)
    charset = %w{ 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H J K L M N O P Q R T U V W X Y Z }
    (0...size).map { charset.to_a[rand(charset.size)] }.join
  end
end

Here is the code to automatically add a masked identifier:

# Include this module in an ActiveRecord object with a column named 'masked_identifier' to
# automatically generate a masked identifier when a new record is saved that can then be used
# to lookup records without revealing how many records have been created
#
# Usage:
# 1) Copy this file into your [rails project]/lib directory
# /lib/has_masked_identifier.rb
#
# 2) Add an initializer to your Rails project
# require 'has_masked_identifier'
#
# 3) Add 'has_masked_identifier' to your ActiveRecord model
# class YourModel < ActiveRecord::Base
#   has_masked_identifier
# end
#
# Optionally, you can include a hash as a parameter to has_masked_identifier that includes a
# custom named column and/or length to override the default 'masked_identifier' column name 
# and/or default length of 8 characters:
# class YourModel < ActiveRecord::Base
#   has_masked_identifier column: 'some_other_column', length: 15
# end

module HasMaskedIdentifier
  def self.included(base)
    base.send :extend, ClassMethods
  end

  module ClassMethods
    attr_accessor :masked_identifier_column, :masked_identifier_length

    def has_masked_identifier(options = {})
      send :include, InstanceMethods
      self.masked_identifier_column = options[:column] || 'masked_identifier'
      self.masked_identifier_length = options[:length] || 8
      before_save :add_masked_identifier, on: :create
    end
  end

  module InstanceMethods
    private

    def add_masked_identifier
      column = self.class.masked_identifier_column
      length = self.class.masked_identifier_length
      raise ArgumentError, 'Column does not exist' unless self.respond_to?(column)
      self[column.to_sym] = CodeGenerator.unique_code(self, column, length)
    end
  end
end

ActiveRecord::Base.send(:include, HasMaskedIdentifier)

Sorry for the lower-than-average quality explanation in this post (I only had about 30 min to pull it together). I’ll come back and improve on it when I turn this into a Rails plugin. That said, I wanted to get this post out there so others could see.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Sun, 01 May 2011 22:55:00 -0700 Dual displays with your MacBook Pro (or any other laptop) http://blog.matthodan.com/running-dual-monitors-with-macbook-pro http://blog.matthodan.com/running-dual-monitors-with-macbook-pro

Note: I was not paid by Plugable to write this post-- I genuinely love their product.

Have you ever wanted to run dual-displays with your MacBook Pro?  With the Plugable USB 2.0 UGA Multi-Display Adapter, it's easy and affordable ($64.50 on Amazon at the time of this writing).  But before we get into details, here is the finished product

Dsc_0063

Yes, I know-- I have three displays hooked up.  Why three?  Why not.  You only need one Plugable adapter (and a Mini DisplayPort adapter) to run two displays, but I thought it would be cool to abandon the Mini DisplayPort and run two Plugable adapters through my USB hub.

As it turns out, abandoning the Mini DisplayPort probably isn't the best option.  The Plugable adapter uses your computer's CPU instead of the graphics chip, so you'll lose CPU cycles if your display is rapidly refreshing a large area (e.g. playing video).  This is by far the most underwhelming thing I noticed-- on my circa 2010 MacBook Pro, there is noticable choppiness when watching fullscreen video at 1920x1080 resolution.  That said if you're not playing video, you probably won't be able to tell the difference between your Mini DisplayPort display and your Plugable display.

My recommendation: Buy one Plugable adapter and keep your second display hooked to the Mini DisplayPort.

Unpacking

Here are some pictures I took while unpacking one of my Plugable adapters:

Dsc_0045
Dsc_0052

As you can see, Plugable includes a bunch of adapters with the standard USB-to-DVI adapter.  With these adapters you can also use the adapter for USB-to-VGA and USB-to-HDMI.

Here is what the adapter looks when hooked up:

Dsc_0061
Dsc_0064

As you can see, the adapter is fairly compact and has a green light that illuminates.  It draws all of its power from the USB line, so no additional power cable necessary.  Sweet!

Installation

Installation was super easy.  You just install a driver and plug in the adapter.  My MacBook Pro automatically recognized the additional display.  The only potential gotcha I noticed is that you download the driver from DisplayLink, not Plugable.  This is because Plugable's adapter wraps DisplayLink's DL-195 chip.  You can download the Mac drivers here:

http://www.displaylink.com/support/mac_downloads.php

I'm using the 1.6 beta 4 version of the drivers and everything is working smoothly.

That's all for now.  You can read more about the Plugable adapter on Plugable's website.  I'll post an update after I've spent some more time using my dual display setup.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Tue, 30 Nov 2010 17:11:20 -0800 Non-Field-Specific Custom Validations and Error Messages in Rails http://blog.matthodan.com/non-field-specific-custom-validations-and-err http://blog.matthodan.com/non-field-specific-custom-validations-and-err
If you've created a moderately complex form in Rails, you've probably asked yourself the question: How do I display a validation error message that doesn't relate to a specific field on my form?

The first solution you should consider is the "error_messages_for" helper.  You can use "error_messages_for" in your view to display a quick and dirty summary of all validation errors.  For example, the following would display a summary of all validation errors on our application's "user" model:

1
<%= error_messages_for :user %>

While not perfect, "error_messages_for" can be customized to show a pretty concise and user friendly error message.  Check out the docs to see all of the output customization options:

What if you only want to show one error message in a specific location that relates to a specific validation?  Enter the good old "error_message_on" helper.  You've probably already used "error_message_on" to display field-specific error messages.  Here is an example that would display an error message on a name field:

1
2
3
4
<%= form_for @user do |f| %>
  <%= f.text_field :name %>
  <%= f.error_message_on :name %>
<% end %>

What many people don't realize is that you can also use "error_message_on" to display non-field-specific error messages!  Consider the following custom validation that checks if a user is both "happy" and "broke":

1
2
3
4
5
6
7
8
9
10
class User < ActiveRecord:Base
  validate :user_is_happy_and_broke

private
  def user_is_happy_and_broke
    if self.state_of_mind != 'happy' || self.fiscal_status != 'broke'
      errors.add :user_not_happy_and_broke, 'User must be happy and broke to continue'
    end
  end
end

Now, to display this custom validation error message with "error_message_on", we simply need to reference ":user_is_happy_and_broke" when we call the helper.  Consider this implementation:

1
2
3
<%= form_for @user do |f| %>
  <%= f.error_message_on :user_not_happy_and_broke %>
<% end %>

W00t!  It works.  Now just format the output with CSS and you're good to go...

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Fri, 20 Aug 2010 08:20:00 -0700 Exclude Static Assets From Heroku Slug Without Removing From Repository Using .slugignore http://blog.matthodan.com/exclude-static-assets-from-heroku-slug-withou http://blog.matthodan.com/exclude-static-assets-from-heroku-slug-withou

Want to reduce the size of your Heroku slug? Easy-- move your static assets to S3.  Great, problem solved, but wait... What do you do with the static assets left in your repository? 

I found myself asking this question today...

My first though was to use .gitignore, which would exclude the static assets from my git repository and in turn my Heroku slug.  However, this approach would leave me without version control of my static assets.  Not ideal...

Then I did a little research and came up with this better approach: .slugignore.  Just like .gitignore, .slugignore sits in your project folder and identifies files to ignore.  However, instead of excluding specified files from your git repository, it excludes them only from your slug.  Genius!

Heroku has a great explanation of .slugignore in their docs. These are some examples of files that Heroku notes you may wish to include in your .slugignore:

  • Unit tests or specs
  • Art sources (like .psd files)
  • Design documents (like .pdf files)
  • Test data (for example, the feedtools gem has 11 megs of XML sample files for its unit tests)

Thanks to Terence Lee and Matthew Todd for helping me discover .slugignore.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Sun, 08 Aug 2010 03:50:41 -0700 Ruby Private Methods vs. Protected Methods http://blog.matthodan.com/ruby-private-methods-vs-protected-methods http://blog.matthodan.com/ruby-private-methods-vs-protected-methods
Let's talk Ruby access control basics... What is the difference between 'private' and 'protected' methods in Ruby?  In Ruby, the primary difference between a 'private' and 'protected' method is that a private method cannot be called with an explicit receiver, while a protected method can.  

What is an 'explicit receiver', you ask?  An explicit receiver is the object that is receiving a message.  In the following example, we have a receiver ('parent') and a method ('get_name').  The 'parent' object is receiving the instruction to perform the 'get_name' method.

parent.get_name

To illustrate that a private method cannot be called by an explicit receiver, consider the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env ruby

class Parent
  private
  def name
    'Mommy'
  end
end

class Child < Parent
  def get_parent_name
    puts name # Implicit receiver
    puts self.name rescue puts 'NoMethodError' # Explicit receiver
    puts Parent.new.name rescue puts 'NoMethodError' # Explicit receiver
  end
end

Child.new.get_parent_name
# => Mommy
# => NoMethodError
# => NoMethodError

We've created a 'Parent' class and a 'Child' class that is a sub-class of Parent.  Parent has a private method 'name' that returns the value 'Mommy'.  When we call 'Child.new.get_parent_name' on line 18, we see the output produced by lines 12-14.  Only when the Parent's method 'name' is called with an implicit receiver do we get a return value.

What does this mean?  This means that private methods can only be called within the context of the current object (since any context outside of the current object would require an explicit receiver).  I.e. one object cannot access another object's private methods.

Extra credit:  Try changing 'private' to 'protected' in the above gist and take a look at the output.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Mon, 02 Aug 2010 00:03:00 -0700 Recurring Payments w/ ActiveMerchant & PayPal Web Payments Pro (US) http://blog.matthodan.com/how-to-add-support-for-paypal-website-payment http://blog.matthodan.com/how-to-add-support-for-paypal-website-payment
Many web services charge recurring subscriptions.  Unfortunately, ActiveMerchant does not support recurring payments with PayPal Website Payments Pro (US) out of the box.  
 
In this tutorial, we will add support for recurring payments to ActiveMerchant.  Before we begin, let’s list what we’re using here: 
  • ActiveMerchant v1.7.0
  • PayPal Website Payments Pro (w/ Recurring Payments Enabled)
  • Rails v2.3.8
  • Ruby v1.8.7 (patchlevel 299)
Note: You do not need to have an active PayPal Website Payments Pro account to test your code.  Instead, create a free PayPal Sandbox (http://sandbox.paypal.com) account. 
 
I. Create PayPal Sandbox Account and Website Payments Pro (US) Test Account 
 
To test your code, you need a PayPal Sandbox account and a Website Payments Pro (US) test account with recurring payments enabled.  Here is how to create the accounts:
 
A) Create PayPal Sandbox Account 
 
1.  Click ‘Sign Up Now’ on the PayPal Sandbox site (http://sandbox.paypal.com) to create a new PayPal Sandbox account.  Once you’ve registered, log in to view the PayPal Sandbox main menu.
 
B) Create Website Payments Pro (US) Test Account with Recurring Payments Enabled 
 
1.  Click ‘Manually Create Accounts’ to create a new Website Payments Pro (US) test account with recurring payments enabled.  Note: You cannot use the ‘preconfigured accounts’ generators, as they do not enable recurring payments. 
 
2.  Click ‘Get Started’ under the section labeled ‘Business’. Select ‘Website Payments Pro’ from the drop down menu and click ‘Continue’ twice.
 
3.  You should see ‘Apply for Website Payments Pro’.  Select ‘Sign Up for a New PayPal Business Account’ and click ‘Sign Up’.
 
4.  Fill out the form with dummy data.  It doesn’t matter what you use here, as it is only for the test account, but make sure to remember the email and password.  When finished, click ‘Agree and Continue’.
 
5.  Continue to fill out the form with dummy data.  You can enter any number in the ‘Federal Tax ID’ field, as long as it’s not all zeros.  I used ‘11-3873926’ and it worked fine.  No need to include any of the ‘optional’ fields (e.g. SSN).
 
6.  Select ‘Recurring Payments’ checkbox on the ‘Products and optional services’ page and then click ‘Continue’.
 
7.  Fill out the form with dummy data.  The credit card information should be pre-populated automatically.  Enter ‘000’ (three zeros) for the ‘CSC’ code and click ‘Submit Application’.
 
C) Confirm Email Address of New Test Account 
 
1.  Click on the ‘PayPal’ logo to return to the Sandbox main page.  Click ‘Test Email’ and look for an email to the dummy email address you used when you created the test account.
 
2.  Copy the URL listed under ‘To activate your account, just confirm your email address.’ and paste it into a new browser window.  Enter your password (The one you used when you created the test account.) and submit the form.
 
D) Verify New Test Account 
 
1.  To verify account, click on ‘Test Accounts’ on the PayPal Sandbox main page.  Select the account that you just created and click ‘Enter Sandbox Test Site’.
 
2.  In the Sandbox Test Site, click the link ‘Get Verified’ on the right side of the page, then click ‘Link Bank Account’.  The bank account numbers should be pre-populated by default.  Enter a dummy ‘Bank Name’ and click ‘Continue’.

3.  Enter dummy values in both of the ‘Deposit Amounts’ fields and click ‘Continue’ twice.  I used ‘$0.25’ and ‘$0.35’ and it worked fine.

E) Retrieve API Credentials for PayPal Test Account

1.  From the PayPal Sandbox main page, click on ‘Test Accounts’.  Select the account that you just created and click ‘Enter Sandbox Test Site’.

2.  Click ‘Profile’ on the Sandbox Test Site main menu, then click ‘Request API Credentials’.  Click ‘Set up PayPal API credentials and permissions’ under ‘Option 1’.  

3.  Click ‘Request API Credentials’ under ‘Option 2’.  Select ‘Request API Signature’ and click ‘Agree and Submit’.  You will see your new API credentials, click ‘Done’ and close the window.

4. From the PayPal Sandbox main page, click ‘API Credentials’.  You should now see a new set of API credentials with a ‘API username’, ‘API password’, and ‘Signature’.  You will use these credentials when you setup ActiveMerchant.

II. Install ActiveMerchant plugin

I won't go into detail here how to install the ActiveMerchant plugin. There are many good tutorials available, but I suggest starting with ActiveMerchant's GitHub (http://github.com/Shopify/active_merchant) and documentation (http://www.activemerchant.org).

A couple key points to consider when installing ActiveMerchant are as follows:

1. The API credentials retrieved for the PayPal test account should be copied to the ActiveMerchant configuration placed in your development.rb file as follows:

2. Once you have a live PayPal Website Payments Pro (US) account, the API credentials should be placed in your production.rb file as follows:

III. Create a wrapper for the PayPal recurring API resources

As shown on the PayPal API Reference, there are four API resources for managing recurring payments:
  • CreateRecurringPaymentsProfile
  • UpdateRecurringPaymentsProfile
  • GetRecurringPaymentsProfileDetails
  • ManageRecurringPaymentsProfileStatus
PayPal manages recurring payments by creating 'payment profiles' that include details about the recurring payment, including the periodicity, amount, payment source, etc. We need to create a wrapper for each of these resources so we can easily interact with the PayPal API to create, update, suspend, and cancel payment profiles.

1. Create a file named 'paypal_recurring_payments.rb' in the following location:

/vendor/plugins/active_merchant/lib/active_merchant/billing/gateways/paypal/

2. Add the following code to the 'paypal_recurring_payments.rb' file:

Note: I haven't wrapped 100% of PayPal's API. I've only wrapped the resources that I needed for my particular application, which was the bare minimum. You should read the PayPal API Documentation to see what additional resources are available. You can modify the 'paypal_recurring_payments.rb' file as needed to fit your project.

3. Open 'paypal.rb' (located in .../gateways/) and add the noted line of code to the top of the file as shown here:

4. Restart your local server if you have it running (plugins are only reloaded on server-startup)

IV. Test your PayPal API wrapper by creating a recurring payment

1. Create a new controller called 'payments_controller.rb'

2. In the 'new' action, add the following code:

Note: You shouldn't use real credit card information for testing purposes. PayPal will provide you with dummy credit cards if you create a new buyer test account in the PayPal Sandbox. You can use the create 'Preconfigured' account option to get new buyer accounts.

3. Add 'map.resources :payments' to your project's routes.rb file for the new resource

4. Add a new view for the resource in 'views/payments/' named 'new.html.erb' with the following code included in the file, so we can read the response from PayPal:

<%=h @response.message %>

5. In your browser, navigate to the resource at http://localhost:3000/payments/new and wait for the PayPal response. If everything worked correctly, you should see 'Success'.

6. Log into your PayPal Sandbox and view the recent activity of the Website Payments Pro (US) test account. You should see that a new recurring payments profile has been created. If you do, congrats! You've just created your first PayPal recurring payment profile.

You can use the 'update_recurring_profile' and 'get_recurring_profile' methods (see paypal_recurring_payments.rb) to update and retrieve profile information. Take note of which fields are required in the PayPal API Documentation. I've also tried to label them in the 'paypal_recurring_payments.rb' file.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Fri, 23 Jul 2010 15:31:00 -0700 Ruby Arrays Containing Country, State, and Province Codes Used by PayPal's API http://blog.matthodan.com/ruby-arrays-containing-country-state-and-prov http://blog.matthodan.com/ruby-arrays-containing-country-state-and-prov

While working on an address form for a rails project, I came across this nasty little task of building an array of country, state, and province codes.  I ended up downloading PayPal's official list of country, state, and province codes from their API documentation and making the following:

Country codes:

U.S. state codes:

Canadian province codes:

Other state/province codes:

Hopefully this saves you the time you would have spent converting PayPal's lists of codes into ruby arrays.

Enjoy!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan
Fri, 04 Jun 2010 19:24:00 -0700 How to setup Heroku Hostname SSL with GoDaddy SSL Certificate and Zerigo DNS http://blog.matthodan.com/how-to-setup-heroku-hostname-ssl-with-godaddy http://blog.matthodan.com/how-to-setup-heroku-hostname-ssl-with-godaddy
Heroku recently added an exciting new 'Hostname SSL' option.  This option offers the broad compatibility of IP-based SSL, but at 1/5 the price ($20 / month at the time of this writing).  
 
The following tutorial explains how to use Heroku's new 'Hostname SSL' option on your Heroku project.  Before we begin, let's list what we're using here:
  • Heroku Hostname SSL
  • GoDaddy Standard SSL Certificate
  • Zerigo DNS
Note: I am not using the Heroku Zerigo DNS add-on, instead I have a separate Zerigo account for my DNS needs.  I do this because Zerigo offers 30 hosts on free direct accounts, versus only 10 hosts on the free Heroku add-on.
 
I. Getting a GoDaddy SSL Certificate (Part I)
 
1. Purchase a GoDaddy Standard SSL Certificate
 
GoDaddy sells Standard SSL Certificates for anywhere from $12.99/year to $49.99/year.  I highly recommend you do a search for 'cheap ssl' on Google and see if there are any advertisements for discounted GoDaddy Standard SSL Certificates.  I was able to buy my certificate for $12.99/year this way.
 
2. After you complete your purchase, GoDaddy will give you a credit that you can trade for a certificate.  Make the trade and click on 'Manage Certificate' next to your new certificate.  This will bring you to a Credits control panel where we will click 'Request Certificate' next to your new certificate later on when we are ready to setup your certificate.
 
II. Creating a Certificate Signing Request (CSR)
 
Note: To create an SSL certificate, you must first generate and submit a Certificate Signing Request (CSR) to the Certification Authority (CA) (i.e. GoDaddy). The CSR contains your certificate-application information, including your public key. The CSR will also create your public/private key pair used for encrypting and decrypting secure transactions.
 
These instructions are based on my experience using a Mac OS X laptop.  The following probably won't work if you are not working from a unix-based system (i.e. Mac OS X / Ubuntu Linux / etc.).
 
Steps to create a CSR:
 
1. Make a new directory to hold your project's SSL-related stuff.  It doesn't really matter where you put this, but I recommend not putting it in your rails project (i.e. alongside app, config, db, etc.), as it will get included in your git repository if you do.  Rather, I put it in a folder that is one level above my rails project.
 
mkdir ssl-cert
 
2. Move to your newly created folder
 
cd ssl-cert
 
3. Use OpenSSL to generate an RSA host key ('host.key') using the triple DES encryption, with a 2,048-bit key length (as required by GoDaddy).  Triple DES is just DES times three, but is more secure against brute force attacks because of its longer length.
 
openssl genrsa -des3 -out host.key 2048
 
It will ask you for a pass phrase.  This should be a secret password.  Don't forget the pass phrase you set, as we will need it later.
 
4. Use OpenSSL to generate a new self-signed certificate ('host.csr') using the host key we just created.  This is what you'll be sending to GoDaddy to model your new SSL after.
 
openssl req -new -key host.key -out host.csr
 
You will be prompted with a bunch of questions.  Answer all of them, except the last two 'extra' attributes are optional.  Here are example responses:
 
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:San Francisco
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Your Company Name
Organizational Unit Name (eg, section) []:secure.yourdomain.com
Common Name (eg, YOUR name) []:secure.yourdomain.com
Email Address []:contact@yourdomain.com

Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
 
It is very important you don't mistype anything here, as you can't change this information without buying a new SSL certificate.  'Organizational Unit Name' and 'Common Name' must be the hostname you are using on Heroku.  I highly recommend using the 'secure.yourdomain.com' host, as you will need to set a separate CNAME DNS record to route your secure traffic.
 
III. Getting a GoDaddy's SSL Certificate (Part II)
 
1. Return to where we left off with GoDaddy.  You should have clicked 'Request Certificate' and see a form where you need to answer the following questions:
 
Where is your certificate going to be hosted? Third Party
Enter your Certificate Signing Request (CSR) below: [copy contents of 'host.csr' here]
Select your certificate issuing organization: GoDaddy
Is this certificate for Intel vPro? No
 
2. Verify everything and then click through to finish.  You should now be able to view and download your GoDaddy SSL certificate from GoDaddy from the 'Manage Certificates' section.
 
IV. Prepare SSL Certificate for Heroku
 
1. Download your new SSL certificate from GoDaddy's website into your 'ssl-cert' directory that we created in step I.  You will get two files from GoDaddy: 'secure.yourdomain.com.crt' and 'gd_bundle.crt'.  'secure.yourdomain.com.crt' is your new SSL certificate.  'gd_bundle.crt' contains the SSL issuing certificate chain back to the root SSL certificate.
 
2. Combine 'secure.yourdomain.com.crt' and 'host.key':
 
cat secure.yourdomain.com.crt host.key > host.pem
 
3. Remove pass phrase from the public key certificate (required by Heroku)
 
openssl rsa -in host.pem -out nopassphrase.pem
openssl x509 -in host.pem >>nopassphrase.pem
 
You will be asked for the pass phrase you set in step I.  I told you to remember it!
 
4. Open 'nopassphrase.pem' in a text editor and delete the 'private key' section:
 
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
 
5. Combine 'gd_bundle.crt' and 'nopassphrase.pem':
 
cat nopassphrase.pem gd_bundle.crt > public.pem
 
'gd_bundle.crt' is a chain file that links your certificate to a original trusted host certificate that GoDaddy owns.
 
6. Remove pass phrase from the private key certificate (required by Heroku)
 
openssl rsa -in host.key -out private.key
 
You will be asked for the pass phrase you set in step I.  I told you to remember it!
 
You might be asking yourself: What do all of these file extensions mean?  Well, here you go:

*.csr -- Certificate Signing Request used for submission to signing authorities that issue SSL certificates
*.crt -- Public key of a certificate (same as a *.pem file, but with different extension).  May include a chain of certificates back to the host certificate.  This is what you'll get from GoDaddy when you download a purchased certificate.
*.pem -- Public key of a certificate (same as a *.crt file, but with different extension).  May include a chain of certificates back to the host certificate.  This is what you'll get from GoDaddy when you download a purchased certificate. 
*.key -- Private key of a certificate
 
V. Add SSL Certificate to Heroku
 
1. Go to the root of your Heroku project folder and add the nopassphrase pem and key to Heroku:
 
heroku ssl:add ../ssl-cert/public.pem ../ssl-cert/private.key
 
You may need to adjust the paths to point to your 'nopassphrase.pem' and 'nopassphrase.key' files.
 
2. If you haven't done so already, you must enable the Heroku custom domains add-on and add 'secure.yourdomain.com' to Heroku's list of domains:
 
heroku addons:add custom_domains:basic
heroku domains:add secure.yourdomain.com
 
3. Next, you need to add Heroku's 'Hostname SSL' solution:
 
heroku addons:add ssl:hostname
 
This will add a $20/month (as of the time of this writing) fee to your Heroku bill for SSL.
 
VI: Setting up your DNS to work with Heroku Hostname SSL
 
1. You should recieve an email from heroku within a few minutes of adding the ssl:hostname addon.  You need to add a CNAME record to your DNS that points to the AWS host in the email you receive.  This should be pretty self explanatory, but if you have any questions, search for 'adding a CNAME record' in Google and you'll see lots of good guides.
 
2. Test that 'host secure.yourdomain.com' outputs 'something.amazonaws.com'.  If it does, you're all set.
 
You should now be able to go to 'https://secure.yourdomain.com' and not see any errors or security warnings.
 
What is going on behind the scenes
 
When a user visits your site using 'https://secure.yourdomain.com', they're hitting your GoDaddy CNAME record, which points to an 'something.amazonaws.com' address which effectively routes the request to Heroku's grid, and a secure connection gets established from there following the standard SSL handshake process.
 
I hope this was helpful!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/667850/sq.png http://posterous.com/users/36jxRgLcth1D Matt Hodan Matt Hodan Matt Hodan