#145 Integrating Active Merchant
In this episode I show how to add Active Merchant's functionality to a Rails application to make a fully-functional checkout process.
- Download:
- source codeProject Files in Zip (108 KB)
- mp4Full Size H.264 Video (30.1 MB)
- m4vSmaller H.264 Video (19.9 MB)
- webmFull Size VP8 Video (50 MB)
- ogvFull Size Theora Video (39.9 MB)
Resources
- Episode 144: Active Merchant Basics
- Active Merchant
- Active Merchant PeepCode PDF
- PayPal's Developer Site
- PayPal's Website Payment Pro Guide PDF
- Nifty Generators
- Full Episode Source Code
Update: As Pawel pointed out in the comments, make sure to add the card numbers to the filter_parameter_logging call in your application.rb file so they are not logged.
bash
rake gems:install script/generate nifty_scaffold order new cart_id:integer ip_address:string first_name:string last_name:string card_type:string card_expires_on:date script/generate model order_transaction order_id:integer action:string amount:integer success:boolean authorization:string message:string params:text
controllers/application.rb
filter_parameter_logging :card_number, :card_verification
config/environment.rb
config.gem "activemerchant", :lib => "active_merchant", :version => "1.4.1"
config/environment/development.rb
config.after_initialize do ActiveMerchant::Billing::Base.mode = :test ::GATEWAY = ActiveMerchant::Billing::PaypalGateway.new( :login => "seller_1229899173_biz_api1.railscasts.com", :password => "FXWU58S7KXFC6HBE", :signature => "AGjv6SW.mTiKxtkm6L9DcSUCUgePAUDQ3L-kTdszkPG8mRfjaRZDYtSu" ) end
config/environment/test.rb
config.after_initialize do ActiveMerchant::Billing::Base.mode = :test ::GATEWAY = ActiveMerchant::Billing::BogusGateway.new end
config/environment/production.rb
config.after_initialize do ActiveMerchant::Billing::Base.mode = :production ::GATEWAY = ActiveMerchant::Billing::PaypalGateway.new( :login => "seller_1229899173_biz_api1.railscasts.com", :password => "FXWU58S7KXFC6HBE", :signature => "AGjv6SW.mTiKxtkm6L9DcSUCUgePAUDQ3L-kTdszkPG8mRfjaRZDYtSu" ) end
orders_controller.rb
def create @order = current_cart.build_order(params[:order]) @order.ip_address = request.remote_ip if @order.save if @order.purchase render :action => "success" else render :action => "failure" end else render :action => 'new' end end
models/cart.rb
has_one :order
models/order.rb
class Order < ActiveRecord::Base belongs_to :cart has_many :transactions, :class_name => "OrderTransaction" attr_accessor :card_number, :card_verification validate_on_create :validate_card def purchase response = GATEWAY.purchase(price_in_cents, credit_card, purchase_options) transactions.create!(:action => "purchase", :amount => price_in_cents, :response => response) cart.update_attribute(:purchased_at, Time.now) if response.success? response.success? end def price_in_cents (cart.total_price*100).round end private def purchase_options { :ip => ip_address, :billing_address => { :name => "Ryan Bates", :address1 => "123 Main St.", :city => "New York", :state => "NY", :country => "US", :zip => "10001" } } end def validate_card unless credit_card.valid? credit_card.errors.full_messages.each do |message| errors.add_to_base message end end end def credit_card @credit_card ||= ActiveMerchant::Billing::CreditCard.new( :type => card_type, :number => card_number, :verification_value => card_verification, :month => card_expires_on.month, :year => card_expires_on.year, :first_name => first_name, :last_name => last_name ) end end
models/order_transaction.rb
class OrderTransaction < ActiveRecord::Base belongs_to :order serialize :params def response=(response) self.success = response.success? self.authorization = response.authorization self.message = response.message self.params = response.params rescue ActiveMerchant::ActiveMerchantError => e self.success = false self.authorization = nil self.message = e.message self.params = {} end end
views/orders/new.html.erb
<% form_for @order do |f| %> <%= f.error_messages %> <p> <%= f.label :first_name %><br /> <%= f.text_field :first_name %> </p> <p> <%= f.label :last_name %><br /> <%= f.text_field :last_name %> </p> <p> <%= f.label :card_type %><br /> <%= f.select :card_type, [["Visa", "visa"], ["MasterCard", "master"], ["Discover", "discover"], ["American Express", "american_express"]] %> </p> <p> <%= f.label :card_number %><br /> <%= f.text_field :card_number %> </p> <p> <%= f.label :card_verification, "Card Verification Value (CVV)" %><br /> <%= f.text_field :card_verification %> </p> <p> <%= f.label :card_expires_on %><br /> <%= f.date_select :card_expires_on, :discard_day => true, :start_year => Date.today.year, :end_year => (Date.today.year+10), :add_month_numbers => true %> </p> <p><%= f.submit "Submit" %></p> <% end %>
views/orders/success.html.erb
SUCCESS!
views/orders/failure.html.erb
FAILURE