Ruby back to basics – Modules and more de-mystified

I often teach Ruby at corporates, take some classes at colleges and speak at some events. Its great when I encounter aggressive and passionate programmers who question and counter question me at every step. These are some of the questions that I have often encountered regarding modules

  • How do I know from an object which all modules are included?
  • How are the methods included from a module resolved and in what order?
  • Can I cherry-pick methods from a module?
  • Can I choose which module method I want to invoke incase the same method is defined in more than one included module?

This got me searching for answers and digging deep into Ruby. And lo and behold, I learnt something new myself. Some of this stuff has been available for ages but very often just ignored or taken for granted or just treated as SEP (as Douglas Adams would put it).

Ruby crushes conventional Object Oriented Concepts

  • In Ruby, all methods (public, protected and private) are available to the inherited classes. That is how we can call include or extend in a Class even though they are defined as private methods in the class Module.
  • In Ruby, private and protected are in the context of an Object and not the Class.

The deal with private and protected is that “Inside a class, we can access the private methods of our own instance i.e. self” but “Inside a class, we can access protected methods of other objects of the same class”. And I thought protected set the method access level for inherited classes!

class Base
  protected
  def foo
    puts "Base:foo"
  end
  private
  def bar
    puts "Base:bar"
  end
end

class Derived < Base
  def test(other)
    other.foo
  end
  def test1(other)
    other.bar rescue puts "Oops.. private method"
  end
end

a1 = Derived.new
a2 = Derived.new
a1.test(a1)       # Base:foo
a1.test(a2)       # Base:foo
a1.test1(a1)      # Oops.. private method # even on self!!
a1.test1(a2)      # Oops.. private method

Ruby Object Hierarchy

This ‘chart’ is straight from the ruby-doc.org and it paints a “pretty” picture :)

Classes, modules, and objects are interrelated. In the diagram that follows, the vertical arrows represent inheritance, and the parentheses meta-classes. All metaclasses are instances of the class `Class’.

                         
                         +---------+             +-...
                         |         |             |
         BasicObject-----|-->(BasicObject)-------|-...
             ^           |         ^             |
             |           |         |             |
          Object---------|----->(Object)---------|-...
             ^           |         ^             |
             |           |         |             |
             +-------+   |         +--------+    |
             |       |   |         |        |    |
             |    Module-|---------|--->(Module)-|-...
             |       ^   |         |        ^    |
             |       |   |         |        |    |
             |     Class-|---------|---->(Class)-|-...
             |       ^   |         |        ^    |
             |       +---+         |        +----+
             |                     |
obj--->OtherClass---------->(OtherClass)-----------...

Basically, Class inherits from Module, Object and BasicObject and all Meta-Classes finally inherit from Class. In simple words - Modules in Ruby is multiple inheritance with a twist!

Cherry picking Modules methods

Of course we know how modules work. However, in the following example, can I choose the instance method foo from module A or module B?

module A
  def foo
    puts "A:foo"
  end
end

module B
  def foo
    puts "B:foo"
  end
end

class Base
  include A
  include B
end

class BaseAgain
  include B
  include A
end

BaseAgain.new.foo   # => A:foo
Base.new.foo        # => B:foo

Suppose I want to call the instance method foo from the A module on the object of Base, can I do so?

class Base
  include A
  include B

  def foo
    A.foo       # incorrect: Cannot call foo like a class method.
  end
end

Base.new.foo     # =>  undefined method `foo' for A:Module

This is correct, since we have included the methods – i.e. all the methods are now instance methods. This is how we can choose which Module method to invoke on an instance.

module A
  def foo
    puts "A:foo"
  end
end

module B
  def foo
    puts "B:foo"
  end
end

class Base
 include A
 include B

 def foo(module_name=A)
    module_name.instance_method(:foo).bind(self).call
 end

end

puts Base.new.is_a?(A)  # => true
puts Base.include?(A)   # => true

Base.new.foo(B)         # => B:foo
Base.new.foo(A)         # => A:foo
Base.new.foo            # => A:foo

The interesting concept unearthed here was that of Bound and Unbound methods.

def foo(module_name=A)
    module_name.instance_method(:foo).bind(self).call
end

This is awesome! instance_method returns an unbound method. These are the naked methods of the module. They cannot be called unless they are bound to an object of that module. Since the class includes that module (under the cover, its safe to say that it inherits from that module), the method can be bound to self and then called.

Now, I can cherry pick which method I want called even if I have included more than one module with the same method name in it!

Posted in Ruby, Tutorials | Tagged | 1 Comment

Real-time Games using HTML5, WebSockets, nodejs and socket.io

Ever imagined playing a game on the web by simply logging in – no local installation required, no licenses and you can continue from where you left off! Imagine multi-player games from your browser or phone – basically ‘gaming in the cloud’. Ok – that sounded pretty cliche :) But its already here folks and faster and better then we can imagine!

What started off as a proof of concept for us has quickly gathered shape to build something of real potential. What we wanted to do was

  • Launch a game on a common display in a web browser.
  • Control the game from different browsers (desktop or mobile).
  • Manage notifications between controllers and the game.
  • Ensure that no installation required what so ever, even as browser plugins.
  • Measure the latency involved.

The Initial Investigation and options

Nodejs boasts of high concurrency, is a Javascript framework and hence functional or event based programming. Sounds awesome but has a higher learning curve. socket.io works very well with WebSockets, so it would be easy to manage

EventMachine also manages high concurrency using evented I/O. Should be an ideal choice for high concurrency but how will websockets be managed easily?

Simply based on a few facts about nodejs and the new stuff we could learn and investigate , we chose nodejs – (and I am happy to say that it may have been a very prudent choice! )

These are the node modules we used:

  • socket.io - the obvious choice for WebSockets.
  • express – our choice of the Web Interface. We could have used a Rails application but seems an overkill.
  • jade – for HTML templates
  • redis – for PubSub.

Getting our act together

We wanted to build something that would give us the data we need as well as be fun! So, we decided to build a game called ‘Tapit’.

Tapit is a dance floor – a place where you can join in by clicking on a unique URL and entering your nickname. You would see your cartoon on the dancefloor and will have the controls on your mobile browser – 4 actions which will change the images on the dance-floor effectively making your cartoon dance! Everyone can have their own cartoon on the dance floor and can dance together. This creates a ‘engaged interaction game’ – where the person has to be in front of the dance floor to see his cartoon dance to his tune! A simple application with huge potential.

So, we started by setting up the node server and the node modules. We also installed Redis on our server to make the most of Redis PubSub!

To install node, npm and the node modules read these links: nodejs and  npm.

Configuring socket.io, express and redis

We can setup our node server and configure it like this:

HOST = "localhost",
PORT = "3001"

var express = require('express')
 , app = express.createServer()
 , redis = require('redis')
 , io = require('socket.io').listen(app);

const DB = redis.createClient();
io.set('log level', 1); // reduce logging

app.use(express.bodyParser());
app.use(express.static(__dirname + '/public'));
app.set('view engine', 'jade');

app.listen(PORT);

We also need to keen the Redis PubSub messaging channels open. Here is how we do this:

io.sockets.on('connection', function(socket) {
  const subscribe = redis.createClient();
  const publish = redis.createClient();

  socket.on('publish', function(channel, data) {
    publish.publish(channel, data);
  });

  socket.on('psubscribe', function(channel) {
    subscribe.psubscribe(channel);
  });

  subscribe.on("pmessage", function(pattern, channel, message) {
    socket.emit('message', { channel: channel, data: message });
  });
});

Create a new dance floor

To create a new dance floor, we need to call URL /games/new from the display machine. This creates the dance floor and gets the client side code ready to listen to new events like ‘new dancers’ or ‘change of action’.

Starting the game

To get your cartoon on the dance floor, users need to type the URL generated for that unique dancefloor on their mobile browser. This shows a screen to get your nickname, so you can identify yourself on the dance floor.

Playing the game

Once you have joined in, you should see your own avatar (cartoon) on the dance floor.

At this same time, you should see 4 controls on your mobile browser. You can tap anyone to make the cartoon on the dance floor ‘make your move’.

This is how the client side JS controls actions are controlled

$("#subscribe").submit(function() {
  socket.emit('psubscribe', $('#subscribe #channel').val());
  return false;
});

$(".action").click(function() {
  socket.emit('publish', 'game.#{gameid}.action.' + $(this).data('action'),
  JSON.stringify({ nick: "#{nick}", ts: Date.now() })
);

The websocket publishes events for a particular game. When nodejs receives this event, it publishes this on Redis PubSub. Since there are listeners connected, they receive this notification. Since listeners can be web-sockets themselves, they get a push notification on the webpage.

Performance – Latency and Concurrency

We tested out various networks, over WiFi, 3G and even on Edge network. The worse case scenario with Edge we found a latency of 200ms – probably acceptable.

When we tested for concurrency, we were easily able to scale easily to 100 ‘dancers on the dance floor’ dancing at the same time. The big issue currently is that for every subscriber I have to open a redis client. So,  I need to figure that one out. The other issue (still in debugging) was “Too many files open” exception on the node server. Again, this is not node related but a setup related issue.

Github repos

I have this game updated on github at http://github.com/joshsoftware/tapit  Feel free to fork it and play around.

Where do we go from here?

This is just the beginning! Our next aim to build a multi-player game on the web. There are constraints of scale and latency – but then let us go where few men have gone before! :)

Posted in Javascript | Tagged , , , | 10 Comments

Upstart Scripts in Ubuntu

Upstart is an event based tool that handles starting of services during system booting and shut-down the services before system is shut down. It also monitors the services while they running. It was designed to overcome the limitations in system V and dependency based init systems.

Limitations in existing systems

  1. They are not dynamic in nature. That means when we plug in a new devise like a monitor after the system has booted up, the system cannot recognize it without user intervention.
  2. There is no parallelism. This means when we start certain services, like mysql which is dependent on some other services, they should start before mysql service has started. To start these dependent services, it requires manual configuration in /etc/rc.X directories and is prone to errors.
  3. In some systems, a brute force approach is used to ensure all dependent services has started. This bring load on the system and is sometimes in-efficient.

To get more limitations on existing systems, you can read more information here. Upstart overcomes these limitations by starting services only when all conditions are met. And there would be no kernel panic if init fails as it is designed in a very clean and sensible way.

Triggering Jobs

Upstart scripts are located in /etc/init/ directory with a .conf extension. The scripts are called ‘System Jobs’ and run using sudo privileges. Just like system jobs we also have ‘User Jobs’ that are located at $HOME/.init/ directory. (Note: Only Ubuntu versions above 11.10 support user jobs). After internal upstart initialization, it emits an event called ‘startup’ which triggers rest of system and user jobs.

Writing Upstart scripts

An Upstart script is a combination of states and events. On particular events the service state changes from one to another. Currently upstart supports 10 states. They are waiting, starting, pre-start, spawned, post-start, running, pre-stop, stopping, killed and post-stop. More details here.  Here is a simple upstart script which starts node.js server whenever system boots.

# /etc/init/nodejs.conf

description "node.js server"
author      "Siva Gollapalli"

# used to be: start on startup
# until we found some mounts weren't ready yet while booting:
#start on started mountall
# If network interface is wireless
start on (local-filesystems and net-device-up IFACE=wlan0)
# If network interface is Ethernet uncomment below line and comment above line
#start on (local-filesystems and net-device-up IFACE=eth0)

stop on shutdown

# Automatically Respawn:
respawn
respawn limit 99 5

script
    # Not sure why $HOME is needed, but we found that it is:
    export HOME="/home/siva/work/myproject"

    exec /usr/local/bin/node $HOME/node/notify.js 13002 >> /var/log/node.log 2>&1
end script

post-start script
   # Optionally put a script here that will notify you node has (re)started
   # /root/bin/hoptoad.sh "node.js has started!"
end script

Stanzas and Configuration

‘description’, ‘author’, ‘start on’, ‘stop on’, ‘respawn’, ‘script’ and ‘post-start’ are called as stanzas.

start on (local-filesystems and net-device-up IFACE=wlan0)

This tells Upstart to start node.js service  when all local-filesystems and wireless network interface is up.

start on (local-filesystems and net-device-up IFACE=eth0)

This tells Upstart to  start node.js service when all local-filesystems are up and Ethernet network interface is up.

Before starting node.js service Upstart executes the pre-start block if it exists. Later it executes the script block which is the actual code used to start a service. After service has been started, upstart executes post-start block.

In our current scenario with node.js service, there are no pre-start block and the post-start block is there with no code. So, upstart just start node.js service without any pre and post actions.

Monitoring services

You may not have noticed that I forgot to explain what is ‘respawn’ and when to use :) ‘respawn’ is a stanza  which executes when the service has exited for some reason and you want start the service again automatically then this will be used.

‘respawn limit’ defines the limit of re-tries for a service. In our current scenario it is 99 times after a time interval of 5 seconds. That means, try 99 times every 5 seconds to get our service started.

Note: It is preferred not to ‘respawn’ unless and until you are sure that the code you have written is correct. Otherwise it could leads to problems on CPU utilization and memory constraints.

After system has been started execute following command to know status of the service


sudo initctl nodejs status

Stopping services

Up till now we have seen how to start a service. When system is about shut down Upstart executes pre-stop block similar to pre-start block and then executes post-stop block after service has been shut down which is similar to post-start. In out current scenario node.js service stops when system is shut down. We do not need to do anything special to stop services on shutdown. Its guaranteed to cleanly shutdown processes in the correct order!

I hope everyone enjoys this article and let me know if you face any complex scenarios to write. I will give a shot. Feedback and suggestions are welcome.

Posted in Tutorials | Tagged , | Leave a comment

Push notifications using express.js and socket.io

So we built a real-time bidding system! Why? Because one of our clients needed it. Our customer bridges the gap between vendors and customers. (Cannot reveal more specifics like the domain etc.)

  • Customer requests an order and vendors bid for that order.
  • Customer should be notified in real-time about any bids.
  • Customer should be able to negotiate with any of the bidders.
  • A negotiation request should be sent to all bidders, so they can be competitive.
  • A vendor should see a negotiation request.
  • A customer can confirm a bid for a vendor.
  • That vendor should get immediate notification and should confirm that bid!
  • blah, blah, blah…

Since this was web application, using websockets was the need of the hour! What we needed was to finalize was putting it all together. We had a choice of socket.io, express.js or backbone.js. (Feel free to remind me of others). Since our Rails server (v3.1) was configured with MongoDB (via Mongoid), we had to get this in place too.

Option 1

Use node.js and its mongodb node_module to setup a notification service between users. A user could connect to the node server (register his login name) and we could control messages to and from that user. The problem is however that the notifications are generated after Rails request processing – this is not a chat service. Shoot!

Option 2

Use express.js to setup a small rack application and route requests to that.  But I would have to manage flow of information – write models, controllers etc. AND it still doesn’t solve my problem of notifications being generated after Rails request processing. Further more, I would need to listen on the client side anyway!

What we did

We run a node server in addition to a Rails server. The node server is powered by socket.io and express.js.

  • socket.io is used for easy notification management from clients.
  • express.js route was to listen for notifications from the Rails server.

So, when a vendor or customer logs in, we connect to the node server and maintain that connected socket connections hash. The express.js routes would be for notifications generated from the Rails server. Using the node connections  hash, we can decide whom to send notifications! The added advantage is that I am not dependent on the database. Here is the gist if you want to see it all. Here are the deeper details:

First we need to configure our node server with express.js AND socket.io. The express.js server is listening on port 13002!


var express = require('express')
, app = express.createServer()
, io = require('socket.io').listen(app);

app.use(express.bodyParser());
app.listen(13002);

Now, lets see how we setup the routes for listening to notifications from the Rails server. We have a generic message sender method which takes the :action and the : recipient whom the message is intended for. The body contains whatever we want to send, typically json data. We shall soon see what the connections contain.


app.get('/', function (req, res) {
 res.send(404);
});

app.post('/message/:action/:to', function (req, res) {
 target = connections[req.params.to]
 if (target) {
  connections[req.params.to].emit(req.params.action, req.body);
  res.send(200);
 }
 else
  res.send(404);
});

We see that connections is critical here. This is where we hook up socket.io into express.js. The connections is a Hash that contains all the connected websockets!


var connections = {}

io.sockets.on('connection', function(socket) {
 socket.on('username', function(username) {
  connections[username] = socket;
 });
});

When a websocket connection is received, we save the connection data into our server connections hash. That way we know who is connected and who should be sent the notification!

Hey! How did the web-sockets get connected anyway? Simple – here is the HTML client side Javascript!


:javascript
  var socket = io.connect('#{NODEJS_HOST}');

  // Connectivity
  socket.emit('username', '#{current_user.name}');

  socket.on('reconnect', function () {
    console.log('Reconnected to the server');
    socket.emit('username', '#{current_user.name}');
  });

  socket.on('reconnecting', function () {
    console.log('Attempting to re-connect to the server');
  });

  // Custom Messages

  socket.on('bid', function(data) {
    $('#notifications').append("<div class='notifications'>" +
    "Bid: Rs." + data.amount + " for " + data.customer +
    "</div>");
  });

What happens here is that when the socket.io gets connected, the socket emits a method with the logged in users name! Thats the name we collect and store in the server connections hash!

We can now customize ANY message like we have done for ‘bid’. It can be passed data directly and can be processed. So, the only missing piece of the puzzle now is how we create and fire notifications from the Rails server!

require 'net/http'

module FX
  module Messenger

    def notify(action, user, data)
      url = "#{NODEJS_HOST}/message/#{action}/#{user}"
      res = Net::HTTP.post_form(URI.parse(URI.encode(url)), data)

      # 200 implies successfully sent.
      # There is nothing we can do if the targe user is not online(404)
      # For any other error, raise Exception
      unless ["200", "404"].include? res.code
        raise Exception.new("Error: #{res.code}")
      end
    end

A sample example of what we have done is on github. Its still in the basic stage (extracted from what we built) but I plan to add full fledge bidding control to it soon.

Ciao!

Posted in Javascript, Ruby on Rails | Tagged , , , , | 9 Comments

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
    build_resource
    if resource.save
      sign_in(resource)
      resource.reset_authentication_token!
      render :template => '/devise/registrations/signed_up' #rabl template with authentication token
    else
      render :template => '/devise/registrations/new' #rabl template with errors
    end
  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 , , | 25 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 | 6 Comments