Github repository:--
https://github.com/shamsulsham89/active_merchant_rails3.2
http://railscasts.com/episodes/145-integrating-active-merchant
Create a new rails 3.2 app as:-
rails new active_merchant_payment
Generate scaffold as:-
rails g scaffold product name price:decimal
rails g scaffold cart purchased_at:datetime
rails g scaffold line_item unit_price:decimal product_id:integer cart_id:integer quantity:integer
rails g scaffold order cart_id:integer ip_address:string first_name:string last_name:string card_type:string card_expires_on:date
rails g model order_transaction order_id:integer action:string amount:integer success:boolean authorization:string message:string params:text
Add in Gemfile:-
gem 'activemerchant'
In routes.rb:-
root :to => 'products#index'
In app/models/cart.rb:--
class Cart < ActiveRecord::Base
attr_accessible :purchased_at
has_many :line_items
has_one :order
def total_price
# convert to array so it doesn't try to do sum on database directly
line_items.to_a.sum(&:full_price)
end
end
In app/models/line_item.rb:--
class LineItem < ActiveRecord::Base
attr_accessible :cart_id, :product_id, :quantity, :unit_price
belongs_to :cart
belongs_to :product
def full_price
unit_price * quantity
end
end
In app/views/products/index.html.erb:-
<h1>Listing products</h1>
<table>
<tr>
<th>Name</th>
<th>Price</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
<% @products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.price %></td>
<td><%= link_to "Add to Cart", line_items_path(:product_id => product), :method => :post %></td>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Product', new_product_path %>
In application_controller.rb:-
def current_cart
if session[:cart_id]
@current_cart ||= Cart.find(session[:cart_id])
session[:cart_id] = nil if @current_cart.purchased_at
end
if session[:cart_id].nil?
@current_cart = Cart.create!
session[:cart_id] = @current_cart.id
end
@current_cart
end
In line_items_controller.rb:-
def create
@product = Product.find(params[:product_id])
@line_item = LineItem.create!(:cart_id => current_cart.id, :product_id => @product.id, :quantity => 1, :unit_price => @product.price)
flash[:notice] = "Added #{@product.name} to cart."
redirect_to cart_url(:current)
end
In carts_controller.rb:--
def show
@cart = current_cart
end
In app/views/carts/show.html.erb:-
<p id="notice"><%= notice %></p>
<h4>Products in Your cart</h4>
<table>
<tr>
<th>Product Name</th>
<th>Unit Price</th>
<th>Full Price</th>
</tr>
<% for line_item in @cart.line_items %>
<tr>
<td><%= line_item.product.name %></td>
<td><%= line_item.unit_price %></td>
<td><%= line_item.full_price %></td>
</tr>
<% end %>
</table>
<h3>Total: <%= number_to_currency @cart.total_price %> </h3>
<p>
<%= link_to "Continue Shopping", products_path %>
<% if @cart.line_items.first %>
|
<%= link_to "Checkout", new_order_url %>
<% end %>
</p>
In app/models/order.rb:--
class Order < ActiveRecord::Base
attr_accessible :card_expires_on, :card_type, :cart_id, :first_name, :ip_address, :last_name
attr_accessible :card_number, :card_verification
belongs_to :cart
has_many :transactions, :class_name => "OrderTransaction"
attr_accessor :card_number, :card_verification
validate :validate_card, :on => :create
validates :first_name, presence: true
validates :last_name, presence: true
validates :card_number, presence: true
validates :card_verification, presence: true
def purchase
response = GATEWAY.purchase(price_in_cents, credit_card, purchase_options) rescue false
unless response
self.errors.add("base", "Unable to make payment")
return false
end
if response.success? == false
errors[:base] << response.message
return false
end
transactions.create!(:action => "purchase", :amount => price_in_cents, :response => response)
cart.update_attribute(:purchased_at, Time.now) if response.success?
response.success?
end
def authorize
response = GATEWAY.authorize(price_in_cents, credit_card, purchase_options) rescue false
puts "*******************"
puts response.inspect
puts "************************"
unless response
errors[:base] << "Unable to authorize credit card"
return false
end
if response.success? == false
if response.avs_result['code'] != "P"
errors[:base] << response.avs_result['message']
return false
end
errors[:base] << response.message
return false
end
transactions.create!(:action => "authorize", :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 => "Shamsul Haque",
:address1 => "Rajiv Chowk",
:city => "New Delhi",
:state => "Delhi",
:country => "India",
:zip => "110027"
},
:x_test_request => false
}
end
def validate_card
unless credit_card.valid?
credit_card.errors.full_messages.each do |message|
errors[:base] << message
end
end
end
def credit_card
@credit_card ||= ActiveMerchant::Billing::CreditCard.new(
:brand => 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
In app/models/order_transaction.rb:-
class OrderTransaction < ActiveRecord::Base
attr_accessible :action, :amount, :authorization, :message, :order_id, :params, :success, :response
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
In app/controllers/orders_controller.rb:--
def new
@order = Order.new
@cart = current_cart
respond_to do |format|
format.html # new.html.erb
format.json { render json: @order }
end
end
def create
@cart = current_cart
@order = Order.new(params[:order])
@order.cart_id = current_cart.id
session[:cart_id] = nil
@order.ip_address = request.remote_ip
if @order.valid?
if @order.save && @order.authorize == true
if @order.purchase
render :action => "success"
else
render :action => "failure"
end
else
render :action => 'new'
end
else
render :action => 'new'
end
end
In app/views/orders:--
Create a new page as success.html.erb and put the line as:-
SUCCESS!
Create a new page as failure.html.erb and put the line as:-
FAILURE!
In config/environments/development.rb:--
ActiveMerchantPayment::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict
# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL)
config.active_record.auto_explain_threshold_in_seconds = 0.5
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
end
ActiveMerchant::Billing::Base.mode = :test
::GATEWAY = ActiveMerchant::Billing::Base.gateway(:authorize_net).new(
:login => "TestMerchant",
:password => "password", :test => 'true')
https://github.com/shamsulsham89/active_merchant_rails3.2
http://railscasts.com/episodes/145-integrating-active-merchant
Create a new rails 3.2 app as:-
rails new active_merchant_payment
Generate scaffold as:-
rails g scaffold product name price:decimal
rails g scaffold cart purchased_at:datetime
rails g scaffold line_item unit_price:decimal product_id:integer cart_id:integer quantity:integer
rails g scaffold order cart_id:integer ip_address:string first_name:string last_name:string card_type:string card_expires_on:date
rails g model order_transaction order_id:integer action:string amount:integer success:boolean authorization:string message:string params:text
Add in Gemfile:-
gem 'activemerchant'
In routes.rb:-
root :to => 'products#index'
In app/models/cart.rb:--
class Cart < ActiveRecord::Base
attr_accessible :purchased_at
has_many :line_items
has_one :order
def total_price
# convert to array so it doesn't try to do sum on database directly
line_items.to_a.sum(&:full_price)
end
end
In app/models/line_item.rb:--
class LineItem < ActiveRecord::Base
attr_accessible :cart_id, :product_id, :quantity, :unit_price
belongs_to :cart
belongs_to :product
def full_price
unit_price * quantity
end
end
In app/views/products/index.html.erb:-
<h1>Listing products</h1>
<table>
<tr>
<th>Name</th>
<th>Price</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
<% @products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.price %></td>
<td><%= link_to "Add to Cart", line_items_path(:product_id => product), :method => :post %></td>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Product', new_product_path %>
In application_controller.rb:-
def current_cart
if session[:cart_id]
@current_cart ||= Cart.find(session[:cart_id])
session[:cart_id] = nil if @current_cart.purchased_at
end
if session[:cart_id].nil?
@current_cart = Cart.create!
session[:cart_id] = @current_cart.id
end
@current_cart
end
In line_items_controller.rb:-
def create
@product = Product.find(params[:product_id])
@line_item = LineItem.create!(:cart_id => current_cart.id, :product_id => @product.id, :quantity => 1, :unit_price => @product.price)
flash[:notice] = "Added #{@product.name} to cart."
redirect_to cart_url(:current)
end
In carts_controller.rb:--
def show
@cart = current_cart
end
In app/views/carts/show.html.erb:-
<p id="notice"><%= notice %></p>
<h4>Products in Your cart</h4>
<table>
<tr>
<th>Product Name</th>
<th>Unit Price</th>
<th>Full Price</th>
</tr>
<% for line_item in @cart.line_items %>
<tr>
<td><%= line_item.product.name %></td>
<td><%= line_item.unit_price %></td>
<td><%= line_item.full_price %></td>
</tr>
<% end %>
</table>
<h3>Total: <%= number_to_currency @cart.total_price %> </h3>
<p>
<%= link_to "Continue Shopping", products_path %>
<% if @cart.line_items.first %>
|
<%= link_to "Checkout", new_order_url %>
<% end %>
</p>
In app/models/order.rb:--
class Order < ActiveRecord::Base
attr_accessible :card_expires_on, :card_type, :cart_id, :first_name, :ip_address, :last_name
attr_accessible :card_number, :card_verification
belongs_to :cart
has_many :transactions, :class_name => "OrderTransaction"
attr_accessor :card_number, :card_verification
validate :validate_card, :on => :create
validates :first_name, presence: true
validates :last_name, presence: true
validates :card_number, presence: true
validates :card_verification, presence: true
def purchase
response = GATEWAY.purchase(price_in_cents, credit_card, purchase_options) rescue false
unless response
self.errors.add("base", "Unable to make payment")
return false
end
if response.success? == false
errors[:base] << response.message
return false
end
transactions.create!(:action => "purchase", :amount => price_in_cents, :response => response)
cart.update_attribute(:purchased_at, Time.now) if response.success?
response.success?
end
def authorize
response = GATEWAY.authorize(price_in_cents, credit_card, purchase_options) rescue false
puts "*******************"
puts response.inspect
puts "************************"
unless response
errors[:base] << "Unable to authorize credit card"
return false
end
if response.success? == false
if response.avs_result['code'] != "P"
errors[:base] << response.avs_result['message']
return false
end
errors[:base] << response.message
return false
end
transactions.create!(:action => "authorize", :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 => "Shamsul Haque",
:address1 => "Rajiv Chowk",
:city => "New Delhi",
:state => "Delhi",
:country => "India",
:zip => "110027"
},
:x_test_request => false
}
end
def validate_card
unless credit_card.valid?
credit_card.errors.full_messages.each do |message|
errors[:base] << message
end
end
end
def credit_card
@credit_card ||= ActiveMerchant::Billing::CreditCard.new(
:brand => 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
In app/models/order_transaction.rb:-
class OrderTransaction < ActiveRecord::Base
attr_accessible :action, :amount, :authorization, :message, :order_id, :params, :success, :response
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
In app/controllers/orders_controller.rb:--
def new
@order = Order.new
@cart = current_cart
respond_to do |format|
format.html # new.html.erb
format.json { render json: @order }
end
end
def create
@cart = current_cart
@order = Order.new(params[:order])
@order.cart_id = current_cart.id
session[:cart_id] = nil
@order.ip_address = request.remote_ip
if @order.valid?
if @order.save && @order.authorize == true
if @order.purchase
render :action => "success"
else
render :action => "failure"
end
else
render :action => 'new'
end
else
render :action => 'new'
end
end
In app/views/orders:--
Create a new page as success.html.erb and put the line as:-
SUCCESS!
Create a new page as failure.html.erb and put the line as:-
FAILURE!
In config/environments/development.rb:--
ActiveMerchantPayment::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict
# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL)
config.active_record.auto_explain_threshold_in_seconds = 0.5
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
end
ActiveMerchant::Billing::Base.mode = :test
::GATEWAY = ActiveMerchant::Billing::Base.gateway(:authorize_net).new(
:login => "TestMerchant",
:password => "password", :test => 'true')