Introduction

Active Merchant is an easy all in one solution for accepting credit card payments. Active Merchant is unique in that it provides a fairly standard interface to more than 100 payment gateways. In this article we will show you how to implement Active Merchant in your Ruby on Rails project. Let's get started.

Rails Version 4.0, 4.1, 4.2
Gems Used activemerchant 1.46
Other Notes Uses the Bootstrap 3.3.1 CSS from bootstrapcdn.

Gem Installation

To start working with Active Merchant, we need to add the gem to our gemfile. Open up your Gemfile and add in the line listed below.

Gemfile:

gem 'activemerchant', '~> 1.46.0'

Now run a bundle install to install the gem.

Terminal Commands:

bundle install

E4 Gateway Setup

For this example we will use First Data's E4 Gateway Demo to test. If you already have a gateway to use, you can skip this section.

If you don't have a gateway, but are unsure, you can create a free test account at First Data's e4 Gateway Demo Site. Once you fill out the form and click the submit button, you should have your login information within a few minutes.

Once you have your login information, sign into the demo site. It will prompt you to create a new password. Do so. Then, once logged in click Administration, then click terminals. You will see 3 listings, one of each ending in RETAIL, MOTO, and ECOMM. Click the one ending ECOMM, it will expand to show a form that looks similar to the one listed below.

Note your gateway id, then click generate next to the password and copy the result and make note if it. You will need both of these items to utilize active merchant.

Rails Application Setup

Now that you have a gateway demo account setup (or you have an existing gateway you can use), you will need to create an initializer to set up Active Merchant. Create a new initializer called activemerchant.rb and add in the code listed below, making sure you replace mylogin with your gateway id and mypassword with the password you generated earlier. Also, it is recommended that you use environment variables or secrets.yml instead of storing the credentials here in order to avoid your sensitive credentials getting checked into source control.

config/initializers/activemerchant.rb:

if Rails.env == "development"
  ActiveMerchant::Billing::FirstdataE4Gateway.wiredump_device = File.open(Rails.root.join("log","active_merchant.log"), "a+")  
  ActiveMerchant::Billing::FirstdataE4Gateway.wiredump_device.sync = true 
  ActiveMerchant::Billing::Base.mode = :test

  login = "mylogin"
  password="mypassword"
elsif Rails.env == "production"
  login = 'mylogin'
  password='mypassword'
end
GATEWAY = ActiveMerchant::Billing::FirstdataE4Gateway.new({
      login: login,
      password: password
})

The code above detects whether we are running under production or development. If we are running under development we set up a log file (that's what the wiredump_device lines do) and enable logging. The ActiveMerchant::Billing::Base.mode = :test tells Active Merchant we wish to use the test version of the gateway we have selected. Note that depending on your gateway, you may need different or additional options. For example, PayFlowPro (both US and UK variants) requires an additional partner field. Unfortunately there is no easy way to determine this, short of Googling the answer or browsing the source code. If you run across any gateways that require additional/different options, feel free to share the gateway and the options you had to use in the comments below so that they can be helpful to others.

The next thing we need to do is create a model in order to try out Active Merchant. For this demo application we will create a model called Payment that will be used to charge credit cards. Run the command below to create this model now.

Terminal Commands:

rails g model Payment first_name last_name last4 amount:decimal{12,3} success:boolean authorization_code

Now run a rake db:migrate to update the database.

Terminal Commands:

rake db:migrate

Next we need to create a controller and views to provide a user interface that will allow us to interact with Active Merchant. Run the commands below to create the Payments controller.

Terminal Commands:

rails g controller Payments index new create

Now we need to set up the routes for our payments controller and add a site root. Open up your routes file and modify it so that it looks like the code listed below.

config/routes.rb:

Rails.application.routes.draw do
  root to: "payments#index"
  resources :payments, only: [:index, :new, :create]
end

Model Setup

Great! Now we'll need to add some code to our model. Open your Payment model and modify it so that it looks like the code listed below.

app/models/payment.rb:

class Payment < ActiveRecord::Base
  require "active_merchant/billing/rails"

  attr_accessor :card_security_code
  attr_accessor :credit_card_number
  attr_accessor :expiration_month
  attr_accessor :expiration_year

  validates :first_name, presence: true
  validates :last_name, presence: true
  validates :card_security_code, presence: true
  validates :credit_card_number, presence: true
  validates :expiration_month, presence: true, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 12 }
  validates :expiration_year, presence: true
  validates :amount, presence: true, numericality: { greater_than: 0 }

  validate :valid_card

  def credit_card
    ActiveMerchant::Billing::CreditCard.new(
      number:              credit_card_number,
      verification_value:  card_security_code,
      month:               expiration_month,
      year:                expiration_year,
      first_name:          first_name,
      last_name:           last_name
    )
  end

  def valid_card
    if !credit_card.valid?
      errors.add(:base, "The credit card information you provided is not valid.  Please double check the information you provided and then try again.")
      false
    else
      true
    end
  end

  def process
    if valid_card
      response = GATEWAY.authorize(amount * 100, credit_card)
      if response.success?
        transaction = GATEWAY.capture(amount * 100, response.authorization)
        if !transaction.success?
          errors.add(:base, "The credit card you provided was declined.  Please double check your information and try again.") and return
          false
        end
        update_columns({authorization_code: transaction.authorization, success: true})
        true
      else
        errors.add(:base, "The credit card you provided was declined.  Please double check your information and try again.") and return
        false
      end
    end
  end
end

This is a bit meaty, so we'll break it down step by step. The first line tells Active Merchant to include the built-in Rails helpers.

Include the Active Merchant Rails Helpers
require "active_merchant/billing/rails"

The next few lines add some attributes to our class to allow for the temporary storage of the credit card fields. We don't store these fields in the database due to security reasons. Once we charge the card we no longer need these fields.

Custom Class Attributes

  attr_accessor :card_security_code
  attr_accessor :credit_card_number
  attr_accessor :expiration_month
  attr_accessor :expiration_year

After the validation lines you'll notice a custom validation called valid_card. This validation is used to validate the card information prior to sending it to the payment processor. Active Merchant includes this functionality, we just need to check it.

Custom Credit Card Validation

  validate :valid_card

  def credit_card
    ActiveMerchant::Billing::CreditCard.new(
      number:              credit_card_number,
      verification_value:  card_security_code,
      month:               expiration_month,
      year:                expiration_year,
      first_name:          first_name,
      last_name:           last_name
    )
  end

Next we have the process method. The process method will attempt to authorize the card first (check to see if the funds are available) and then charge the card. If the transaction is successful, the process method then updates the authorization_code and success fields. If the transaction was unsuccessful, a validation error is added to the model.

The Process Method

def process
    if valid_card
      response = GATEWAY.authorize(amount * 100, credit_card)
      if response.success?
        transaction = GATEWAY.capture(amount * 100, response.authorization)
        if !transaction.success?
          errors.add(:base, "The credit card you provided was declined.  Please double check your information and try again.") and return
          false
        end
        update_columns({authorization_code: transaction.authorization, success: true})
        true
      else
        errors.add(:base, "The credit card you provided was declined.  Please double check your information and try again.") and return
        false
      end
    end
  end
end

Controller Setup

Now that we have our model in place, we can start working on our controllers and views. Open up your Payments controller and modify it so that it looks like the code listed below.

app/controllers/payments_controller.rb:

class PaymentsController < ApplicationController
  def index
    @payments = Payment.all
  end

  def new
    @payment = Payment.new
  end

  def create
    @payment = Payment.new(payment_params)

    if @payment.save
      if @payment.process
        redirect_to payments_path, notice: "The user has been successfully charged." and return
      end
    end
    render 'new'
  end

private
  def payment_params
    params.require(:payment).permit(:first_name, :last_name, :credit_card_number, :expiration_month, :expiration_year, :card_security_code, :amount)
  end
end

In the create method you will notice that we first save the record and then we proceed to process the card. If any of those steps fail, the user is sent back to the new payment page. Other then that, it's mostly standard Rails controller code here.

Helpers Setup

For this example app we have 2 helpers. The first helper, months, generates a month list for our month drop down list. The second helper, years, generates a years list for our years drop down list. Open up your payments helper and modify it so that it looks like the code listed below.

app/helpers/payments_helper.rb:

module PaymentsHelper
  def months
    (1..12).collect{|n| ["#{n} - #{Date::MONTHNAMES[n]}", n]}
  end

  def years
    (Time.now.year..Time.now.year+15)
  end
end

View Setup

Now that we have created our model and controller, it's time to build the views themselves. First, let's modify our application layout to include Bootstrap. Bootstrap will pretty things up a bit for us.

app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
<head>
  <title>ActiveMerchantExampleApp</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
  <%= stylesheet_link_tag "http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" %>
</head>
<body>
<div class="container">
<%= yield %>
</div>
</body>
</html>

Next we'll create an index view for the Payments controller. The index view records all the payment attempts. A payment attempt for the purposes of this example is any attempt to charge the card via our payment processor. Open up the index view for the payments controller and modify it so that it looks like the code listed below.

app/views/payments/index.html.erb:

<h1>Payment Attempts</h1>
<div class="well">
<%= link_to "New Payment", new_payment_path, class: "btn btn-primary" %>
</div>
<% if !flash[:notice].blank? %>
  <div class="alert alert-success">
    <%= flash[:notice] %>
  </div>
<% end %>
<table class="table table-bordered table-striped">
  <tr>
    <th>First Name</th>
    <th>Last Name</th>
    <th>Last 4</th>
    <th>Amount</th>
    <th>Succeeded?</th>
    <th>Authorization Code</th>
  </tr>
  <% if @payments.size > 0 %>
    <% @payments.each do |payment| %>
      <tr>
        <td><%= payment.first_name %></td>
        <td><%= payment.last_name %></td>
        <td><%= payment.last4 %></td>
        <td><%= number_to_currency payment.amount %></td>
        <td><%= payment.success == true ? "Yes" : "No" %></td>
        <td><%= payment.authorization_code %></td>
      </tr>
    <% end %>
  <% else %>
    <tr>
      <td colspan="5">No payments have been attempted.</td>
    </tr>
  <% end %>
</table>

Next we'll create the new view for the Payments controller. The new view contains a form that allows us to enter the user's information in order to charge the card. Open up the new view for the payments controller and modify it so that it looks like the code listed below.

app/views/payments/new.html.erb:

<div class="row">
  <div class="col-xs-6 col-xs-offset-3">
    <h1>New Payment</h1>

    <% if @payment.errors.any? %>
      <div class="alert alert-danger">
        <ul>
          <% @payment.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
        </ul>
      </div>
    <% end %>
    <div class="well">
      <%= form_for @payment do |f| %>
        <div class="form-group">
          <%= f.label :first_name, class: "control-label" %>
          <%= f.text_field :first_name, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :last_name, class: "control-label" %>
          <%= f.text_field :last_name,class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :credit_card_number, class: "control-label" %>
          <%= f.text_field :credit_card_number, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :expiration_month, class: "control-label" %>
          <%= f.select :expiration_month, months, {}, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :expiration_year, class: "control-label" %>
          <%= f.select :expiration_year, years, {}, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :card_security_code, class: "control-label" %>
          <%= f.text_field :card_security_code, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :amount, class: "control-label" %>
          <%= f.number_field :amount, class: "form-control", step: "0.01" %>
        </div>
        <div class="form-group">
          <%= f.submit "Charge Credit Card", class: "btn btn-primary" %>
        </div>
      <% end %>
    </div>
  </div>
</div>

Testing Our App and Final Words

Now that we have our application built it's time to test. First, go visit the site GetCreditCardNumbers.com. This site has a number of generated credit card numbers for you to test with. Make note of one, since we'll use it to test with. Next, start your Rails server and navigate to your Rails application. Once there, click the new payment button and fill out the information. Once you filled out the form, clicking Charge Credit Card should successfully charge the card and return you to the index page. If there is an error the app should let you know and return you to the new payment page so that you can make changes and try again.

That's it! Thanks for reading!