Saturday, September 8, 2007

Stuff I learned getting ActiveMerchant to work on Rails

I'm an intermediate or less level user of Ruby on Rails, and I have been recently trying to get ActiveMerchant to work so that I can charge people's credit cards over the internet. The funny thing about software writing is that there really is no central repository of information on how to do it...well there is, it's called google, and when you run into a problem you just hope and pray that when you cut and paste the error message into google it will find some blog, bulletin board, or chat archive where someone had the same problem as you did, AND at the same time, one of these magical uber uber uber geeks will come out of the ether and arrogantly berate some idiot peon like me while reluctantly providing the "simple" solution thick with sarcasm. Yes these are the ranks one must bear as you climb your way through the muck of software mediocrity, but just think, once you get it figured out you'll be able to show your boss the cool app you built and hear gratifying accolades like "Um, ok, but can you make the letters green?"

Well just in case your trying to get ActiveMerchant to work on rails with authorize.net here are the main problems I ran into that took me a day or two to figure out because I nothing came up on google.

1.) when you install the gem make sure you go "sudo gem install activemerchant -y"... the "-y" makes sure all the dependencies get installed.

2.) in addition to putting "require 'active_merchant'" in your config/environment.rb file (right at the bottom of the file), you must also put "include ActiveMerchant::Billing" at the top of your controller within the class.

example your_controller.rb:


require 'money'
class YourController < ApplicationController
include ActiveMerchant::Billing


If you don't do this you will get an error that says something like "uninitialized constant ActiveMerchant::Billing::AuthorizeNetGateway" and you will pull your hair out trying to figure out how to fix it because apparently everyone else on the internet natively knows that you are supposed to do this and no one has ever needed to ask this question or no uber uber uber geek has felt generous enough to answer it when they did, so when you google the above mentioned error nothing really comes up (hopefully now it will though thanks to me).

3.) Finally, if you want the transactions on your app to run in test mode, but you don't want to set your entire Authorize.net account to test mode (like if you have another app using it and setting it to test mode might make you lose money), then what you need to do is NOT use the " ActiveMerchant::Billing::Base.gateway_mode = :test if RAILS_ENV != "production"" setting in your config/environment.rb like everyone else says to. If you do it won't work because apparently this is for some kind of "test" authorize.net account, and won't even work on your real authorize.net account (You'll get a response code 103 back from authorize.net which says something like your account is inactive or your username and password is wrong). To put the transactions from your app in test mode its easy (once you spend 3 hours googling it and finally figure it out), when you build the gateway in the action that charges the card just do this:

gateway = ActiveMerchant::Billing::AuthorizeNetGateway.new({:login => user, :password => pass, :test => 'true'})


And then just remove the ":test => 'true'" parameter, when you are ready to really get people's money.

So a typical payment submission action might look something like this in it's early stages:


def purchase

amount = Money.new('1000', 'USD')

creditcard = ActiveMerchant::Billing::CreditCard.new(
:first_name => Dax,
:last_name => Ewbank,
:number => 1234123412341234,
:month => 01,
:year => 2010,
:verification_value => 123,
:type => master
)

if creditcard.valid?
gateway = ActiveMerchant::Billing::AuthorizeNetGateway.new({:login => user, :password => pass, :test => 'true'})
response = gateway.purchase(amount, creditcard)

if response.success?
##do something if it all works out
else

raise StandardError.new( response.message )

end
end

end


So anyway, if your as dumb as I am about all this maybe what I figured out here will save you the 2 solid days of hair pulling frustration in making this all work.

I got it all working now, but I sure wished that I could have run along this post when I was doing it, it would have saved me alot of time. So here it is for your reference. uber uber uber geeks leave me alone, I know I probably screwed something up in here and your all laughing at me, but hey, I got it to work.

Glad I could help...