-
Notifications
You must be signed in to change notification settings - Fork 4
Samurai Rails Demo Instructions
git clone https://github.com/FeeFighters/samurai-rails-demo.git
cd samurai-rails-demo
gem install bundler
bundle install
rake db:setup
rails s
Open: http://127.0.0.1:3000
rails g model Order user_id:integer article_id:integer
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
rake db:migrate
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
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
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
...
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
gem 'samurai'
Then, run bundler:
bundle install
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'
}
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 %>
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 %>
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
Restart the server and hit http://127.0.0.1:3000
rails s
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) %>
Restart the server and hit http://127.0.0.1:3000
rails s
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; }