Skip to content
This repository was archived by the owner on Mar 10, 2023. It is now read-only.

Samurai Rails Demo Instructions

seanharper edited this page Aug 19, 2011 · 14 revisions

Get started with a basic blog-style app...

Prerequisites

git clone https://github.com/FeeFighters/samurai-rails-demo.git
cd samurai-rails-demo

gem install bundler
bundle install
rake db:setup

Start up server, test out "before" app

rails s

Open: http://127.0.0.1:3000

Prepare for adding Samurai payment processing...

Add an Order model to join User and Article

rails g model Order user_id:integer article_id:integer

Modify the models to setup the associations

class Order < ActiveRecord::Base
  belongs_to :user
  belongs_to :article
end

class Article < ActiveRecord::Base
  has_many :orders
  has_many :users, :through => :orders
  ...
end

class User < ActiveRecord::Base
  has_many :orders
  has_many :articles, :through => :orders
end

Migrate the database

rake db:migrate

Don't show the articles unless they have been purchased

Modify articles_controller.rb:

def show
  @article = current_user.articles.find_by_id(params[:id])
  redirect_to articles_path, :alert=>'You must purchase this article in order to view it' and return if @article.nil?
end

Stub out OrdersController before Samurai integration

Generate a new OrdersController:

rails g controller Orders payment_method transaction create

We now have these controller actions:

class OrdersController < ApplicationController
  # Create/Update a payment method via Samurai Transparent Redirect
  def payment_method
  end

  # Transparent Redirect callback, setup new transaction with the PaymentMethod
  def transaction
  end

  # Create the transaction & handle the result
  def create
  end
end

Rearrange the routes so that orders are nested under articles:

resources :articles do
  get 'payment_method' => "orders#payment_method"
  get 'transaction' => "orders#transaction"
  resources :orders, :only=>[:create]
end    

Redirect to the OrdersController if user hasn't purchased yet

Modify articles_controller.rb:

def show
  @article = current_user.articles.find_by_id params[:id]
  if @article.nil?
    @article = Article.find params[:id]
    redirect_to article_payment_method_path(@article) and return
  end
...

Add $ amount to articles

Modify article.rb:

attr_accessible :name, :content, :amount

Modify articles/_form.html.erb:

<p>
  <%= f.label :amount %><br />
  <%= f.text_field :amount %>
</p>

Generate migration for adding amount field:

rails g migration add_amount_to_articles amount:float

Modify db/seeds.rb to add prices for initial articles:

Article.create :name => 'Awesome Article', :amount => 111.0, :content => ...
Article.create :name => 'Samurai Rocks', :amount => 222.0, :content => ...
Article.create :name => 'Post Three', :amount => 333.0, :content => ...

Drop database and recreate:

rake db:drop && rake db:create && rake db:migrate && rake db:seed

Time to add Samurai!

Add Samurai to your Gemfile:

gem 'samurai'

Then, run bundler:

bundle install

Add Samurai initializer

Add the following (with these demo credentials or your own) to a samurai initializer (ex - config/initializers/init-samurai.rb):

require 'samurai'
Samurai.options = {
  :site => 'https://samurai.feefighters.com/v1/',
  :merchant_key => '197199ef0872afd92c39ceb0',
  :merchant_password => '663b6c16fe50179d7f771c5d',
  :processor_token => '6e340c55559335bf73c8de29'
}

Hook up Samurai

PaymentMethod form

Modify orders_controller.rb:

include Samurai::Rails::Helpers

before_filter do
  @article = Article.find(params[:article_id])
end

Setup PaymentMethod form for transparent redirect:

def payment_method
  setup_for_transparent_redirect(params)
end

Modify payment_method.html.erb:

<h1>Purchase article: <%= @article.name %></h1>
<%= render Samurai::Rails::Views.errors :transaction => @transaction, :payment_method => @payment_method %>+
<%= render Samurai::Rails::Views.payment_method_form :payment_method => @payment_method,
                                                     :redirect_url => article_transaction_url(@article),
                                                     :sandbox => true %>

<%= link_to 'Back to the Articles', articles_path %>  

Transaction form

Setup transaction confirmation in orders_controller.rb:

def transaction
  load_and_verify_payment_method(params)
  redirect_to article_payment_method_path(@article, payment_method_params) and return unless @payment_method
end

Modify transaction.html.erb:

<h1>Confirm Your Purchase</h1>
<h2><%= @article.name %></h2>

<p>
  <strong>Amount:</strong>
  <%= number_to_currency @article.amount %>
</p>
<p>
  <strong>Credit Card:</strong>
  <em>XXXX XXXX XXXX</em> <%= @payment_method.last_four_digits %>
  (<%= "%02d" % @payment_method.expiry_month %> / <%= "%04d" % @payment_method.expiry_year %>)
</p>

<%= link_to 'Submit This Purchase', article_orders_path(@article, :payment_method_token=>@payment_method.token), :method=>:post %>

Transaction #create action

Create the transaction! orders_controller.rb:

def create
  load_and_verify_payment_method(params)
  @order = current_user.orders.create :article=>@article

  @transaction = Samurai::Processor.the_processor.purchase(
    @payment_method.token,
    @article.amount,
    {:descriptor => @article.name, :customer_reference => current_user.id, :billing_reference => @order.id}
  )

  if @transaction.failed?
    @order.destroy
    redirect_to article_payment_method_path(@article, payment_method_params) and return
  end

  redirect_to article_path(@article), :notice=>'Thanks for purchase this article!'
end

Test it out!

Restart the server and hit http://127.0.0.1:3000

rails s

Store the PaymentMethod with the User

Generate a new migration:

rails g migration add_payment_method_token_to_users payment_method_token:string

Run the migration:

rake db:migrate

Modify the OrdersController#payment_method action to pre-load a PaymentMethod:

def payment_method
  params[:payment_method_token] ||= current_user.payment_method_token
  setup_for_transparent_redirect(params)
end

Store the PaymentMethod on the user after the transparent redirect:

def transaction
  ...
  current_user.update_attributes :payment_method_token=>@payment_method.token
end

Redirect directly to the transaction confirmation, if the user already has a card. Modify articles_controller.rb:

def show
  @article = current_user.articles.find_by_id params[:id]
  if @article.nil?
    @article = Article.find params[:id]
    redirect_to article_transaction_path(@article, :payment_method_token=>current_user.payment_method_token) and return if current_user.payment_method_token
    redirect_to article_payment_method_path(@article) and return
  end
  ...
end

Add link on transaction confirmation (views/orders/transaction.html.erb) to change the credit card:

<%= link_to 'Use a different credit card', article_payment_method_path(@article) %>

Test it out!

Restart the server and hit http://127.0.0.1:3000

rails s

Samurai is now successfully processing transactions for your app!

For fun, show the purchased status on the articles#index

Modify articles_helper.rb:

module ArticlesHelper
  def purchased?(article)
    article.users.include?(current_user)
  end
end

Modify articles/index.html.erb:

<div id='articles'>
  <% for article in @articles %>
    <h2>
      <%= link_to article.name, article %>
      <span class="<%= 'purchased' if purchased?(article) %>"><%= purchased?(article) ? 'Purchased' : number_to_currency(article.amount) %></span>
    </h2>
    <p><%= truncate article.content, :length=>100 %></p>
  <% end %>
</div>

Add some styles to application.css:

fieldset { border: none; }

#articles h2 span {
  font-size: 0.7em;
  padding-left: 20px;
}
#articles h2 span.purchased { color: #CCC; }
Clone this wiki locally