Authorize Net (AIM) payment integration with rails

Authorize Net (AIM) method enables internet merchants to accept online payments via credit card. We shall see how to integrate authorize net payment gateway inside a rails app to accept online payments using activemerchant library.

  # Gemfile
  gem 'activemerchant', :require => 'active_merchant'

Register for authorize net sandbox account click here

Payment gateway credentials

# config/authorize_net.yml
development: &development
    mode: test
    login: 9gdLh6T
    key: 67fu45xw6VP92LX1

production:
   <<: *development

test:
   <<: *development

Payment & creditcard form

# app/views/payments/new
= form_for @payment, :url => payments_url do |f|
  = f.text_field :amount
  = fields_for :creditcard, @creditcard do |cc|
    = cc.text_field :name
    = cc.text_field :number
    = cc.select :month, Date::ABBR_MONTHNAMES.compact.each_with_index.collect{|m, i| [m, i+1]}, {:prompt => 'Select'}
    = cc.select :year, Array.new(15){|i| Date.current.year+i}, {:prompt => 'Select'}
    = cc.text_field :verification_value
  = f.submit 'Pay'

Payments Controller

# app/controllers/payments_controller.rb
class PaymentsController < ApplicationController

  def new
    @payment = Payment.new
    @creditcard = ActiveMerchant::Billing::CreditCard.new
  end

  def create
    @payment = Payment.new(params[:payment])
    @creditcard = ActiveMerchant::Billing::CreditCard.new(params[:creditcard])
    @payment.valid_card = @creditcard.valid?
    if @payment.valid?
      @payment = @payment.process_payment(@creditcard)
      if @payment.success?
        @payment.save
        flash[:notice] = I18n.t('payment.success')
        redirect_to payments_url and return
      else
        flash[:error] = I18n.t('payment.failed')
      end
    end
    render :action => :new
  end
end

Generate & Migrate Payment Model

  rails g model payment status:string amount:float transaction_number:string
  rake db:migrate

Payment Model

# app/models/payment.rb
class Payment < ActiveRecord::Base

  PROCESSING, FAILED, SUCCESS = 1, 2, 3

  validates :valid_card, :inclusion => {:in => [true], :message => 'Invalid Credit Card'}
  validates :amount, :presence => true, :numericality => { :greater_than => 0 }

  def process_payment(creditcard)
    ActiveMerchant::Billing::Base.mode = auth['mode'].to_sym
    self.status = PROCESSING
    response = gateway.purchase(amount * 100, creditcard)

    if response.success?
      self.transaction_number = response.subscription_id
      self.status = SUCCESS
    else
      self.status = FAILED
    end
    return self
  rescue Exception => e
    self.status = FAILED
    return self
  end

  def success?
    self.status == SUCCESS
  end

  private
  def gateway
    ActiveMerchant::Billing::AuthorizeNetGateway.new(
      :login    => auth['login'],
      :password => auth['key'])
  end

  def auth
    @@auth ||= YAML.load_file("#{Rails.root}/config/authorize_net.yml")[Rails.env]
  end
end

Posted in Ruby on Rails | Leave a comment

Designing Rails API using Rabl and Devise

Most of us are aware that enabling API access for rails application is easy as Rails provides RESTful APIs by default. However, a little complexity arises when some responses are expected in xml format (maybe for some legacy system) and JSON format. Complexity increases when these API calls need authentication.

The initial obvious thought that comes to ones mind is to create different views for each format and add respond_to block in controller. No! You don’t have to do this.

Rabl

Rabl is a gem which comes in handy when you want to represent the response in both json and xml using a single template. These are the only 2 formats currently supported.

We can enable API for an existing application or new application – the steps are same! Lets see how we

  • enable APIs without authentication.
  • enable APIs with authentication.

Enabling API access without authentication

  • Add ‘rabl’ entry to your Gemfile
  • You might need to add json/xml parser gem to your Gemfile if don’t have them already
  • Execute ‘bundle update’

Now, lets enable json & xml api response for https://localhost/tasks for getting list of tasks. Create the content file

#app/views/tasks/index.rabl

collection @tasks
attributes :id, :name, :priority, :complete_at, :task_type

In the above code we only  mention the attributes that are need to be rendered. There is no need to change tasks_controller code if you haven’t used respond_to for specifying the supported format.  Otherwise, you need insert the following code inside the respond_to block of index method of tasks_controller

#app/controllers/tasks_controller.rb#index

def index
  # some code

  respond_to do |format|
   format.json{}
   fromat.xml{}
  end
end

All set! Now, lets now test the responses for json and xml format by using curl:

curl -v -H "Accept: application/json" -H "Content-type: application/json" https://localhost/tasks.json -k

[{"task":{"name":"Inform users", "task_type":"email", "priority":1, "id":2, "completed_at":null}}, {"task": {"name":"Update Bank or Building Society", "task_type":"document", "priority":1, "id":3, "completed_at":null}}]

curl -v -H “Accept: application/xml” -H “Content-type: application/xml” https://localhost/tasks.xml -k

<?xml version="1.0" encoding="UTF-8"?>
<tasks type="array">
  <task>
    <task-type>email</task-type>
    <name>Inform users</name>
    <completed_at nil="true"></completed_at>
    <id type="integer">2</id>
    <priority type="integer">1</priority>
  </task>

  <task>
    <task-type>document</task-type>
    <name>Update Bank or Society</name>
    <completed_at nil="true"></completed_at>
    <id type="integer">3</id>
    <priority type="integer">1</priority>
  </task>
</tasks>

So with single rabl template we can serve two different formats.

Enabling API access with authentication

Let us consider devise as authentication mechanism. Enable token_authenticatable along with other required devise modules in user model and run migration

#app/models/users.rb
devise :token_authenticatable

We also need to add a migration for this

#db/migrate/20111201074702_add_token_authenticatable_to_users.rb
class AddTokenAuthenticatableToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :authentication_token, :string
  end

  def self.down
    remove_column :users, :authentication_token
  end
end

Enable/uncomment the following line in devise configuration, :auth_token is the name of the parameter be passed in the user for authentication

config.token_authentication_key = :auth_token

For sign_in and sign_up, devise takes care of most of the things. But if you want authentication_token as a response for sign_up/sign_in you need to do the following

  • Add the fields in user model ‘attr_accessor’ to be shown/emitted in the response. For example, if you want email and authentication_token to be part of your response, we need to modify the model like this

#app/models/user.rb
attr_accessible :email, :authentication_token

  •  Modify RegistrationsController create method. The following snippet shows us an example for json format sign_up request with api_key check

#app/controllers/registrations_controller#create
format.json {
  if !params[:api_key].blank? and params[:api_key] == API_KEY
    resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
    sign_in(resource_name, resource)
    current_user.reset_authentication_token!
    respond_with resource, :location => after_sign_in_path_for(resource)
  else
    render :json => {'errors'=>{'api_key' => 'Invalid'}}.to_json, :status => 401
  end
}
format.any{super}

Suppose we have a pre-registered API_KEY as ‘mprmzayb’, we can use it to generate and retrieve an authentication token!

curl -v -H “Accept: application/json” -X POST -d ‘user”:{“email”:”email@email.com”, “password”:”password”, “password_confirmation”:”password”, “accept_terms”:1}}’ https://localhost/users.json?api_key=mprmzayb -k

{"user":{"accept_terms":true, "authentication_token":"VBXdiVeCDGQD3Rxtg9qp", "email":"email@email.com", "has_email_reminder":false}}

Now, if you need the task list API requires authentication (i.e. the authenticate_user! before_filter is enabled for index method of TasksController), we need to pass the authentication_token in the request from sign_in/sign_up request.

Assuming you have the index.rabl in place as shown above, lets test this out:

curl -v -H “Accept: application/json” -H “Content-type: application/json”  https://localhost/tasks.json?auth_token=VBXdiVeCDGQD3Rxtg9qp -k

[{"task":{"name":"Inform users","task_type":"email","priority":1,"id":2,"completed_at":null}},{"task":{"name":"Update Bank or Building Society","task_type":"document","priority":1,"id":3,"completed_at":null}}]

Yeah! Devise automatically takes care of authentication, so in the following senerios appropriate error message is returned.

  • If the user tries to access tasks after logout with old token

{"error":"Invalid authentication token."}

  • If the user tries to access tasks without authentication token

{"error":"You need to sign in or register before continuing."}

Enjoy building your APIs in Rails!

Posted in Ruby on Rails | Tagged , , | 8 Comments

Sencha Touch MVC application with Rails

For sometime, we have been toying around with different frameworks to build cross-platform mobile applications. Our latest research was with Sencha Touch. This post is a tutorial to get kick-started.

Installation

To run Sencha Touch application you need:

  1. A running web server. I used a Rails server running on localhost:3000
  2. A WebKit based browser like chrome or safari.
  3. Sencha Touch SDK.

After downloading the SDK, extract it to the public/javascripts directory of your web application. We typically need only  ”sencha-touch.js” and “resources/css/sencha-touch.css”. You may remove the remaining files.

Configuring the User Agent

I used Safari to test my application. To make it work, I needed to change its User agent to Safari iOS 4.1 iPhone. To change the User agent in Safari, you can go to Menu -> Develop -> User Agent and set the one you need.

In Chrome, refer how to change the user agent of browser.

Rembember Sencha Touch uses HTML5.  In case you require to support requests from a web-application as well as mobile devices (as is in most cases), in the rails application we need some modifications:

  • A method to check that the request is coming from a web browser or a mobile. To do so, modify your application controller as described at Railscasts episode 199. Here is a snippet:

# application_controller.rb
  class ApplicationController < ActionController::Base

    helper :all
    protect_from_forgery
    def mobile_device?
      user_agent = request.user_agent
      user_agent =~ /Mobile|webOS/
    end
   helper_method :mobile_device?
  end

Here we are checking that if user agent of request contains ‘Mobile’ or not, as

  • Safari on Windows has user agent as “Mozilla/5.0 (Windows; U; Windows NT 6.0; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27″.
  • Mozilla Firefox on Ubuntu has user agent as “Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20100101 Firefox/7.0.1″.
  • Safari installed on Ubuntu on Wine with user agent as Safari iOS4.1 iPhone has user agent as “Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7″
  • Android Mobile phone has user agent as “Mozilla/5.0 (Linux; U; Android 2.3.4; en-gb; GT-I9100G Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1″.
  • Update the application layout. (app/views/layouts/application.html.erb)

<!DOCTYPE html>
<html>
  <head>
  <title>Senchamvc</title>
  <%= csrf_meta_tag %>
  <% if mobile_device? %>
    <%= stylesheet_link_tag 'sencha-touch' %>
    <%= javascript_include_tag 'sencha-touch-1.1.1/sencha-touch' %>
    </head>
    <body>
    </body>
    </html>
  <% else %>
    <%= stylesheet_link_tag :all %>
    <%= javascript_include_tag :defaults %>
    </head>
    <body>
      <%= yield %>
    </body>
    </html>
  <% end %>

You can notice that for mobile devices we are not adding ‘yeild’ in body of layout as we have added for web application’s code, this is because all view rendering is going to be  done by the included javascripts.

Now lets see how to write code for our application using the Sencha Touch SDK.

We are building a very simple application. There are 2 models:

  • Business – This is any corporate, company or registered profit making entity.
  • Organization – This is any non-profit organization like NGOs, NPOs etc.

The larger product maps businesses with organizations they support. For the sake of our demo, we are simply using these 2 models to list information. This will help us understand Sencha Touch SDK.

First,create a directory named “app” under public/javascripts. In that create a directory structure like this:


Under the public/javascripts/app directory, create directories named models, controllers and views. These are exactly similar to a standard MVC Rails application.
So application_layout will look like this,

<!DOCTYPE html>
<html>
  <head>
    <title>Senchamvc</title>
    <%= csrf_meta_tag %>
    <% if mobile_device? %>
      <%= stylesheet_link_tag 'sencha-touch' %>
      <%= javascript_include_tag 'sencha-touch-1.1.1/sencha-touch' %>
      <%= javascript_include_tag 'app/app' %>
      <%= javascript_include_tag 'app/routes' %>
      <%= javascript_include_tag 'app/views/Viewport' %>
      <%= javascript_include_tag 'app/views/TabBarMvc' %>
      <%= javascript_include_tag 'app/models/business' %>
      <%= javascript_include_tag 'app/models/organization' %>
      <%= javascript_include_tag 'app/controllers/business' %>
      <%= javascript_include_tag 'app/controllers/organization' %>
      <%= javascript_include_tag 'app/views/business/index' %>
      <%= javascript_include_tag 'app/views/business/show' %>
      <%= javascript_include_tag 'app/views/organization/index' %>
      </head>
      <body></body>
      </html>
    <% else %>
      <%= stylesheet_link_tag :all %>
      <%= javascript_include_tag :defaults %>
      </head>
      <body>
        <%= yield %>
      </body>
      </html>
    <% end %>

Sencha application is initialized from app.js. My application initialization starts with listing of businesses so my public/javascripts/app/app.js looks like this:

new Ext.Application({
  name: 'senchamvc',
  defaultUrl: 'business/index',
  launch: function() {
    this.views.viewport = new senchamvc.views.Viewport();
  }
});

Now lets see what exactly we are doing here,

  • Ext is the global namespace for the whole Sencha Touch framework. Every class, function and configuration for the whole framework exists under this single global variable.
  • Ext.Application represents the entire application.
  • name: ‘senchamvc’ creates a global variable called ‘senchamvc’ – all of your Application’s classes (such as its Models, Views and Controllers) will reside under this single namespace.
  • defaultUrl: When the app is first loaded, this url will be redirected to.
  • when all of your JavaScript are loaded, your application’s launch function is called, at which time you can run the code that starts your app. The launch function is only expected to be run once.
  • Viewport extends from Ext.Container, it has as layout ( defaults layouts is Ext.Layout.Card). This means you can add items to it at any time, from anywhere in your code. Viewport for an application is defined in app/views/Viewport.js

Routing the requests

We routes the request to specific action of controller using app/routes.js

Ext.Router.draw(function(map) {
  map.connect(':controller/:action');
});

The Router is used to map url to controller/action pairs. Every Ext.application can set up Routes using the default Ext.Router instance. So request to url  “business/index” will be dispatched to index action of controller registered as “business”.

The Model

The Business model can be defined as shown below in the app/models/business.js file

senchamvc.models.Business = new Ext.regModel('Business', {
  fields: [
    {name: 'id' , type: 'int'},
    {name: 'name', type: 'string'},
    {name: 'address', type: 'string'}
   ]
});

Here,

  • Ext.regModel:  Registers a model definition i.e creates a new Model class from the specified config object
  • fields : specify the attributes of a model.

To increase performance, we can sync data from remote Rails server to a local data store at time of application initialization. For this I keep 2 data stores in my application, one is remote data store and another is local data store. So, I add this to my business.js model

senchamvc.stores.remoteBusinesses = new Ext.data.Store({
  id: 'remoteBusinesses',
  model: 'Business',
  proxy: {
    type: 'ajax',
    url: 'http://localhost:3000/businesses.json',
    reader: {
      type: 'json',
      root: 'businesses',
      record: 'business'
    },
    writer: {
      type: 'json',
      record: 'business'
    }
  }
});

senchamvc.stores.localBusinesses = new Ext.data.Store({
  id: 'localBusinesses',
  model: 'Business',
  proxy: {
    type: 'localstorage',
    id: 'businessses'
  }
});

Here we are defining the data stores with their proxies. The Store class contains the client side cache of model objects. Stores load data via a Proxy.

Now lets see various attributes of Store,

  • id: is the id we are assigning to data Store.
  • model: specify the model for which we are defining the Store.
  • proxy: Proxies are used by stores to handle the loading and saving of Model data.
  • proxy type: json: Configuration is automatically turned into an Ext.data.AjaxProxy instance, with the url we specified being passed into AjaxProxy’s constructor. So when we call load() on store makes a request to the url we configured.
  • proxy type: localstorage: The LocalStorageProxy uses the new HTML5 localStorage API to save Model data locally on the client browser.
  • reader in this case is JSON Reader is used by a Proxy to read a server response that is sent back in JSON format.
  •  the business data is nested an additional level inside the “businesses” as each “business” item has additional data surrounding it, so we specify “record” i.e within the JSON response that the record data itself can be found at and “root” i.e the name of the property which contains the Array of row objects.

Every time we sync data from the server, it is necessary to clear local data store before syncing it with remote data store. This is to avoid  data inconsistency. We can use far more superior techniques in production systems to sync only deltas. Here I am clearing this, so that we can study the concept of listeners! Update the business.js model

senchamvc.stores.remoteBusinesses.addListener('load', function () {
  var store = Ext.getStore('localBusinesses');
  store.getProxy().clear();
  store.data.clear();
  store.sync();
  this.each(function (record) {
    var business = senchamvc.stores.localBusinesses.add(record.data)[0];
  });
  senchamvc.stores.localBusinesses.sync();
});

The Controller

Moving onto controllers, we ensure that when we initialize the Business controller, we load both the data stores. The app/controllers/business.js looks like this:

Ext.regController('business',{
  init: function(options) {
    senchamvc.stores.remoteBusinesses.load();
    senchamvc.stores.localBusinesses.load();
  }
});

Here Ext.regController: Creates a new Controller class .

To show list page of businesses, in index method of business controller set the active item in Viewport as business index view.

index: function(options) {
  senchamvc.stores.localBusinesses.load();
  if (! this.indexView)
  {
    this.indexView = this.render({
    xtype: 'BusinessIndex',
    });
  }
  senchamvc.views.viewport.setActiveItem(this.indexView, options.animation);
},

You can notice here that we are rendering “BusinessIndex” instead of just index, this is because we are registering the views also, so if we want to register more than 1 index views of different controllers, it will lead to confusion so we are registering index view of business as BusinessIndex. While rendering we are mentioning xtype because every component has a specific xtype, which is its Ext-specific type name.

The View

In the view we can define title of page, store from which you want to show the data, action to be handled on tap event etc. Our Business index (app/views/business/index.js) is as follows,

senchamvc.views.BusinessIndex = Ext.extend(Ext.Panel, {
  dockedItems: [{
    xtype: 'toolbar',
    title: 'Businesses',
    items: []
   }],
  layout: {
    type: 'vbox',
    align: 'center',
    pack: 'center'
  },
  items: [{
    xtype: 'list',
    id: 'businessesindex',
    scroll: 'vertical',
    width: Ext.Element.getViewportWidth()*0.9,
    store: senchamvc.stores.localBusinesses,
    style: {
      background: '#ffffff'
    },
    itemTpl: new Ext.XTemplate(
      '<tpl for=".">',
        '<div>',
          '{name}',
        '</div>',
        '<div>',
          '{address}',
        '</div>',
      '</tpl>'
    ),
    onItemDisclosure: function(record){
    },
    onItemTap: function(item) {
      record = this.getRecord(item);
      Ext.dispatch({
        controller: 'business',
        action: 'show',
        id: record.getId(),
        animation: {type: 'slide', direction: 'left'}
      });
    }
  }],
  initComponent: function() {
    senchamvc.stores.localBusinesses.load();
    senchamvc.views.BusinessIndex.superclass.initComponent.apply(this, arguments);
  }
});
Ext.reg('BusinessIndex', senchamvc.views.BusinessIndex);

Now lets see what exactly we are doing in the view definition,

  • Panel is a container which is building block for user interfaces.
  • dockedItems: A component or series of components to be added as items to panel, items can be docked to either the top, right, left or bottom of a panel. This is typically used for things like toolbars or tab bars.
  • layout should be defined for child items to be correctly sized and positioned, if not then the default layout manager will be used which does nothing but render child components sequentially into the Container (no sizing or positioning will be performed in this situation).
  • items can be single or array of child Components to be added in Container.
  • within items we can specify the properties such as width, scrolling style etc. for Container.
  • One thing you will notice here that is we are defining 2 events, onItemDisclosure and onItemTap. This is because onItemDisclosure display a disclosure icon on each list item. This won’t bind a listener to the tap event. By setting dipatch configuration to an action, it will automatically add a tap event listeners to the disclosure button [not to  entire row]. So as to add listener to entire row we are defining listener for onItemTap event.
  • At the end we are registering this view as BusinessIndex so from a controller we can render this view using the name with which it is registered.

So my application is ready to go with data stored locally.

You can clone the complete example from github.

For more information you can refer to sencha touch application with ruby on rails.

References :

For adding Tabbar to mobile application I refered to sencha-touch-tabbar-in-a-mvc-application.

To generate an installable, such as for android *.apk, of your code please refer to phonegap documentation.

Also an excellent example for MVC application in sencha with phonegap.

At the end I was able to develop this application which shows list of businesses and organizations,


Posted in Mobile Development, Ruby, Sencha | Tagged | 1 Comment