Year in review 2015

Year 2015 was an exciting year for BigBinary !

We added more clients. We increased our team size. We wrote more blogs, spoke at more conferences, and made even more videos !

Here is the breakdown.

We love conferences

We presented at 10 conferences across 7 countries, on topics from Rails to ReactJS.

We are all in ReactJS

We at BigBinary adopted ReactJS pretty early. Early in the year we published series of videos titled Learn ReactJS in steps which takes a “Hello World” app into a full TODO application using ReactJS in incremental steps.

Vipul and Prathamesh are currently authoring a book on ReactJS. Check it out at ReactJS by Example- Building Modern Web Applications with React Book

We also started an ios app using React Native. It’s coming along pretty good and soon we should see it in app store.

We authored many blogs

We love sharing our experiences via blogs on various topics like ReactJS, Rails, React Native and Robot framework etc. Here are some of our blogs from 2015.

Video Summary

Open Source

Apart from our team members contributing to various OpenSource projects, we also support some projects from our team. This year, we added and helped build following projects-

  • Wheel : Wheel is our Rails template for new Ruby on Rails projects, with sane defaults and setups for different environments, and common functionalities like image uploaders, debugging, etc.
  • Mail Interceptor : Interception, Forwarding emails in Ruby on Rails application
  • Handy : A collection handy tools and Rails tasks for your Project.
  • Learn ReactJS in Steps : Collection of examples from Learn ReactJS in step video series.
  • DoceboRuby : Ruby wrapper for Decobo LMS API
  • Doctsplit Chef : Check cookbox for docsplit ruby gem
  • Fixtures Dumper : Dump your Rails data to fixtures easily to a database to populate data.

Community Engagement

Along with speaking at various conferences, we also helped organize, our Fun edition of Pune’s regional RubyConf, DeccanRubyConf, and supported other Indian Conferences, including RubyConfIndia, GardenCity RubyConf.

We also help Pune’s local ruby meetup, which had a splendid engagement this year.

Overall we are super excited about what we accomplished in year 2015. We are looking forward to an exciting year of 2016!

Test runner in Rails 5

This blog is part of our Rails 5 series.

If you run bin/rails -h in a Rails 5 app, you will see a new command for running tests.

$ bin/rails -h
Usage: rails COMMAND [ARGS]

The most common rails commands are:
 generate    Generate new code (short-cut alias: "g")
 console     Start the Rails console (short-cut alias: "c")
 server      Start the Rails server (short-cut alias: "s")
 test        Run tests (short-cut alias: "t")

Before Rails 5, we had to use bin/rake test to run tests. But in Rails 5, we can use bin/rails test. It is not just replacement of old rake task but it is backed by a test runner inspired from RSpec, minitest-reporters, maxitest and others.

Let’s see what bin/rails test can do.

Running a single test

Now it is possible to run a single test out of the box using the line number of the test.

$ bin/rails test test/models/user_test.rb:27

Rails will intelligently run the test from user_test.rb having line number 27. Note that the line number 27 does not need to be first line of the test. Below is an example.

22: def test_valid_user
23:   hash = { email: 'bob@exmaple.com',
24:            first_name: 'John',
25:            last_name: 'Smith' }
26:
27:   user = User.new hash
28:
29:   assert user.valid?
30: end

In the above case, test_valid_user can be run as long as the line number provided is between 22 and 30.

Running multiple tests

You can also pass multiple test paths and Rails will run all of those tests.

$ bin/rails test test/models/user_test.rb:27 test/models/post_test.rb:42

It is also possible to run all tests from a directory.

$ bin/rails test test/controllers test/integration

Improved failure messages

When a test fails, Rails displays a command which can be used to just run the failed test.

$ bin/rails t
Run options: --seed 51858

# Running:

.F

Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>


bin/rails test test/controllers/posts_controller_test.rb:15

I can simply copy bin/rails test test/controllers/posts_controller_test.rb:15 and rerun the failing test.

Failing fast

By default when a test fails then rails reports about the test failures and then moves on to the next test. If you want to stop running the test when a test fails then use option -f.

$ bin/rails t -f
Run options: -f --seed 59599

# Running:

..F

Failure:
PostsControllerTest#test_should_get_new:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>


bin/rails test test/controllers/posts_controller_test.rb:15

Interrupted. Exiting...


Finished in 0.179125s, 16.7481 runs/s, 22.3308 assertions/s.

3 runs, 4 assertions, 1 failures, 0 errors, 0 skips

Defer test output until the end of the full test run

By default when a test fails then rails prints F and then details about the failure like what assertion failed and how to re run the test etc.

If you want to have a clean output of . and F and would like all the test failures report to come at the every end then use option -d.

$ bin/rails t -d
Run options: -d --seed 29906

# Running:

..F...F

Finished in 0.201320s, 34.7704 runs/s, 49.6721 assertions/s.

  1) Failure:
PostsControllerTest#test_should_create_post [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19]:
"Post.count" didn't change by 1.
Expected: 3
  Actual: 2


  2) Failure:
PostsControllerTest#test_should_get_new [/Users/prathamesh/Projects/fun/rails-5-test-runner-app/test/controllers/posts_controller_test.rb:15]:
Expected response to be a <success>, but was a <302> redirect to <http://test.host/posts>

7 runs, 10 assertions, 2 failures, 0 errors, 0 skips

Failed tests:

bin/rails test test/controllers/posts_controller_test.rb:19
bin/rails test test/controllers/posts_controller_test.rb:15

Better backtrace output

By default when an error is encountered while running the test then the output does not contain full stacktrace. This makes debugging little bit difficult.

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007f86bc62b728>
    app/controllers/posts_controller.rb:29:in `create'
    test/controllers/posts_controller_test.rb:20:in `block (2 levels) in <class:PostsControllerTest>'
    test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest

Now we can use -b switch, which will display complete backtrace of error message.

$ bin/rails t -b

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007fc53c4eb868>
    /rails-5-test-runner-app/app/controllers/posts_controller.rb:29:in `create'
    /sources/rails/actionpack/lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
    /sources/rails/actionpack/lib/abstract_controller/base.rb:183:in `process_action'
    /sources/rails/actionpack/lib/action_controller/metal/rendering.rb:30:in `process_action'
    /sources/rails/actionpack/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
    /sources/rails/activesupport/lib/active_support/callbacks.rb:126:in `call'
.....
    /sources/rails/activesupport/lib/active_support/testing/assertions.rb:71:in `assert_difference'
    /rails-5-test-runner-app/test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest>'

Leveraging power of Minitest

The test runner also leverages power of minitest by providing some handy options.

Switch -s to provide your own seed

Now we can also provide our own seed using -s switch.

$ bin/rails t --s 42000

Switch -n to run matching tests

Switch -n will run tests matching the given string or regular expression pattern.

$ bin/rails t -n "/create/"
Run options: -n /create/ --seed 24558

# Running:

E

Error:
PostsControllerTest#test_should_create_post:
NameError: undefined local variable or method `boom' for #<PostsController:0x007faa39c2df90>
    app/controllers/posts_controller.rb:29:in `create'
    test/controllers/posts_controller_test.rb:20:in `block (2 levels) in <class:PostsControllerTest>'
    test/controllers/posts_controller_test.rb:19:in `block in <class:PostsControllerTest>'


bin/rails test test/controllers/posts_controller_test.rb:18

Finished in 0.073857s, 13.5396 runs/s, 0.0000 assertions/s.

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

Verbose output

It is also possible to see the verbose output using -v switch. It shows time required to run each test. This would help in detecting slow running tests.

$ bin/rails t -v
Run options: -v --seed 30118

# Running:

PostsControllerTest#test_should_destroy_post = 0.07 s = .
PostsControllerTest#test_should_update_post = 0.01 s = .
PostsControllerTest#test_should_show_post = 0.10 s = .
PostsControllerTest#test_should_create_post = 0.00 s = F

Failure:
PostsControllerTest#test_should_create_post:
"Post.count" didn't change by 1.
Expected: 3
  Actual: 2

bin/rails test test/controllers/posts_controller_test.rb:19

PostsControllerTest#test_should_get_new = 0.02 s = .
PostsControllerTest#test_should_get_index = 0.01 s = .
PostsControllerTest#test_should_get_edit = 0.00 s = .

Finished in 0.210071s, 33.3220 runs/s, 47.6028 assertions/s.

7 runs, 10 assertions, 1 failures, 0 errors, 0 skips

Colored output

Now by default we will get colored output. No need to add additional gem to colored output.

colored test output

With all these awesome features, testing Rails 5 apps has definitely become a better experience. Rails has shipped all these features within the framework itself so you don’t have to use multiple gems and libraries to achieve all of these things.

ApplicationRecord in Rails 5

This blog is part of our Rails 5 series.

Rails 5 beta-1 was recently released and one of the notable change was introduction of ApplicationRecord.

Upto Rails 4.2, all models inherited from ActiveRecord::Base. But starting from Rails 5, all models will inherit from ApplicationRecord.

class Post < ApplicationRecord
end

What happened to ActiveRecord::Base ?

Well not much changed in reality. Following file will be automatically added to models in Rails 5 applications.

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

This behavior is similar to how controllers inherit from ApplicationController instead of inheriting from ActionController::Base.

Now ApplicationRecord will be a single point of entry for all the customizations and extensions needed for an application, instead of monkey patching ActiveRecord::Base.

Say I want to add some extra functionality to Active Record. This is what I would do in Rails 4.2.

module MyAwesomeFeature
  def do_something_great
    puts "Doing something complex stuff!!"
  end
end

ActiveRecord::Base.include(MyAwesomeFeature)

But now, ActiveRecord::Base forever includes MyAwesomeFeature and any class inheriting from it also includes MyAwesomeFeature even if they don’t want it.

This is especially true if you are using plugins and engines where monkey patching to ActiveRecord::Base can leak into engine or plugin code.

But with ApplicationRecord, they will be localized to only those models which are inheriting from ApplicationRecord, effectively only to your application.

class ApplicationRecord < ActiveRecord::Base
  include MyAwesomeFeature

  self.abstract_class = true
end

Migrating from Rails 4

By default all new Rails 5 applications will have application_record.rb. If you are migrating from Rails 4, then simply create app/models/application_record.rb as shown below and change all models to inherit from ApplicationRecord instead of ActiveRecord::Base.

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

Explicitly ssh into vagrant machine

After building vagrant machine the command to ssh into the guest machine is pretty simple.

vagarnt ssh

While working with chef I needed to explicitly ssh into the vagrant machine. It took me sometime to figure it out.

The key is command vagrant ssh-config. The output might look like this.

$ vagrant ssh-config
Host vmachine
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/nsingh/code/vagrant-machine/.vagrant/machines/vmachine/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL
  ForwardAgent yes

Open ~/.ssh/config and paste the output at the end of the file and save the file.

Now I can ssh into vagrant machine using ssh command as shown below.

ssh vmachine

If you are wondering from where the name vmachine came then this is the name I had given to my vagrant machine .

How constant lookup and resolution works in Ruby on Rails

When a Rails application involving multiple gems, engines etc. are built then it’s important to know how constants are looked up and resolved.

Consider a brand new Rails app with model User.

class User
  def self.model_method
    'I am in models directory'
  end
end

Run User.model_method in rails console. It runs as expected.

Now add file user.rb in lib directory.

class User
  def self.lib_method
    'I am in lib directory'
  end
end

Reload rails console and try executing User.model_method and User.lib_method. You will notice that User.model_method gets executed and User.lib_method doesn’t. Why is that?

In Rails we do not import files

If you have worked in other programming languages like Python or Java then in your file you must have statements to import other files. The code might look like this.

import static com.googlecode.javacv.jna.highgui.cvCreateCameraCapture;
import static com.googlecode.javacv.jna.highgui.cvGrabFrame;
import static com.googlecode.javacv.jna.highgui.cvReleaseCapture;

In Rails we do not do that. That’s because DHH does not like the idea of opening a file and seeing the top of the file littered with import statements. He likes to see his files beautiful.

Since we do not import file then how does it work?

In Rails console when user types User then rails detects that User constant is not loaded yet. So it needs to load User constant. However in order to do that it has to load a file. What should be the name of the file. Here is what Rails does. Since the constant name is User Rails says that I’m going to look for file user.rb.

So now we know that we are looking for user.rb file. But the question is where to look for that file. Rails has autoload_path. As the name suggests this is a list of paths from where files are automatically loaded. Rails will search for user.rb in this list of directories.

Open Rails console and give it a try.

$ rails console
Loading development environment (Rails 4.2.1)
irb(main):001:0> ActiveSupport::Dependencies.autoload_paths
=> ["/Users/nsingh/code/bigbinary-projects/wheel/app/assets",
"/Users/nsingh/code/bigbinary-projects/wheel/app/controllers",
"/Users/nsingh/code/bigbinary-projects/wheel/app/models",
"/Users/nsingh/code/bigbinary-projects/wheel/app/helpers"
.............

As you can see in the result one of the folders is app/models. When Rails looks for file user.rb in app/models then Rails will find it and it will load that file.

That’s how Rails loads User in Rails console.

Adding lib to the autoload path

Let’s try to load User from lib directory. Open config/application.rb and add following code in the initialization part.

config.autoload_paths += ["#{Rails.root}/lib"]

Now exit rails console and restart it. And now lets try to execute the same command.

$ rails console
Loading development environment (Rails 4.2.1)
irb(main):001:0> ActiveSupport::Dependencies.autoload_paths
=> ["/Users/nsingh/code/bigbinary-projects/wheel/app/lib",
"/Users/nsingh/code/bigbinary-projects/wheel/app/assets",
"/Users/nsingh/code/bigbinary-projects/wheel/app/controllers",
"/Users/nsingh/code/bigbinary-projects/wheel/app/models",
"/Users/nsingh/code/bigbinary-projects/wheel/app/helpers"
.............

Here you can see that lib directory has been added at the very top. Rails goes from top to bottom while looking for user.rb file. In this case Rails will find user.rb in lib and Rails will stop looking for user.rb. So the end result is that user.rb in app/models directory would not even get loaded as if it never existed.

Enhancing a model

Here we are trying to add an extra method to User model. If we stick our file in lib then our user.rb is never loaded because Rails will never look for anything in lib by default. If we ask Rails to look in lib then Rails will not load file from app/models because the file is already loaded. So how do we enhance a model without sticking code in app/models/user.rb file.

Introducing initializer to load files from model and lib directories

We need some way to load User from both models and lib directories. This can be done by adding an initializer to config/initializers directory with following code snippet

%w(app/models lib).each do |directory|
  Dir.glob("#{Rails.root}/#{directory}/user.rb").each {|file| load file}
end

Now both User.model_method and User.lib_method get executed as expected.

In the above case when first time user.rb is loaded then constant User gets defined. Second time ruby understands that constant is already defined so it does not bother defining it again. However it adds additional method lib_method to the constant.

In that above case if we replace load file with require file then User.lib_method will not work. That is because require will not load a file if a constant is already defined. Read here and here to learn about how load and require differ.

Using ‘require_relative’ in model

Another approach of solving this issue is by using require_relative inside model. require_relative loads the file present in the path that is relative to the file where the statement is called in. The desired file to be loaded is given as an argument to require_relative

In our example, to have User.lib_method successfully executed, we need to load the lib/user.rb. Adding the following code in the beginning of the model file user.rb should solve the problem. This is how app/models/user.rb will now look like.

require_relative '../../lib/user'

class User
  def self.model_method
    'I am in models directory'
  end
end

Here require_relative upon getting executed will first initialize the constant User from lib directory. What follows next is opening of the same class User that has been initialized already and addition of model_method to it.

Handling priorities between Engine and App

In one of the projects we are using engines. SaleEngine has a model Sale. However Sale doesn’t get resolved as path for engine is neither present in config.autoload_paths nor in ActiveSupport::Dependencies.autoload_paths. The initialization of engine happens in engine.rb file present inside lib directory of the engine. Let’s add a line to load engine.rb inside application.rb file.

require_relative "../sale_engine/lib/sale_engine/engine.rb"

In Rails console if we try to see autoload path then we will see that lib/sale_engine is present there. That means we can now use SaleEngine::Engine.

Now any file we add in sale_engine directory would be loaded. However if we add user.rb here then the user.rb mentioned in app/models would be loaded first because the application directories have precedence. The precedence order can be changed by following statements.

engines = [SaleEngine::Engine] # in case there are multiple engines
config.railties_order = engines + [:main_app]

The symbol :main_app refers to the application where the server comes up. After adding the above code, you will see that the output of ActiveSupport::Dependencies now shows the directories of engines first (in the order in which they have been given) and then those of the application. Hence for any class which is common between your app and engine, the one from engine will now start getting resolved. You can experiment by adding multiple engines and changing the railties_order.

Further reading

Loading of constants is a big topic and Xavier Noria from Rails core team has made some excellent presentations. Here are some of them

We have also made a video on How autoloading works in Rails.

Using Stripe API in React Native with fetch

Stripe makes it easy to accept payments online. Stripe offers an npm package with nice documentation.

Problem with using Stripe in React Native

I added stripe to my React Native application using following command.

npm install stripe --save

Added Stripe to the project as shown below.

var stripe = require('stripe')('stripe API key');

And now I’m getting following error.

could not mount

This’s because npm package uses stripe.js and stripe.js needs http provided by Node.JS.

Our React Native code does not actually run on Node.JS. I know while building React Native we use NPM and we have a node server running in the background so it feels like we are in Node.JS land and we can use everything Node.JS has to offer. But that’s not true. React Native code can’t depend on Node.JS because Node.JS is not shipped with ios. It means we can’t use any of Node.JS packages including http. It means we can’t use stripe npm module.

Now you can remove require('stripe') line that was added in the last step.

Solution

React Native comes with Fetch api. From the documentation

The Fetch API provides a JavaScript interface for accessing an manipulating parts of the HTTP pipeline, such as requests and responses. It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.

stripe.js is a nice wrapper around stripe api. stripe api is very well documented and is easy to use. Since we can’t use stripe.js we will use stripe api.

We will use fetch to create a credit card token using api.

return fetch('https://api.stripe.com/v1/tokens', {
  method: 'post',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Bearer ' + '<YOUR-STRIPE-API-KEY>'
  },
  body: formBody
});

Here, the header has 3 keys. Lets go through them one-by-one:

  • 'Accept': 'application/json' : Designates the content to be in JSON format.
  • 'Content-Type': 'application/x-www-form-urlencoded' : This tells the endpoint that the payload will be one giant query string where name and value pairs will be separated by the ampersand.
  • 'Authorization': 'Bearer ' + '<YOUR-STRIPE-API-KEY>' : This key is to authorize our actions on Stripe. Here Bearer is just a prefix which we need to attach to the api-key because Stripe uses OAuth 2.0 . You can read more on the Bearer token usage here .

Payload needs to contain credit card details.

var cardDetails = {
  "card[number]": '1111 2222 3333 4444',
  "card[exp_month]": '01',
  "card[exp_year]": '2020',
  "card[cvc]": '123'
};

Since the Content-Type is application/x-www-form-urlencoded, the payload should be one query string. An example of this would be: city=Miami&state=Florida

Let’s prepare a proper payload.

var formBody = [];
for (var property in cardDetails) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(cardDetails[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

That’s it. Now we can attach formBody to the body part of the fetch request and we are good to go.

Final solution

Here’s the whole code snippet.

"use strict";

var stripe_url = 'https://api.stripe.com/v1/'
var secret_key = '<YOUR-STRIPE-API-KEY>'

module.exports.createCardToken = function (cardNumber, expMonth, expYear, cvc) {
  var cardDetails = {
    "card[number]": cardNumber,
    "card[exp_month]": expMonth,
    "card[exp_year]": expYear,
    "card[cvc]": cvc
  };

  var formBody = [];
  for (var property in cardDetails) {
    var encodedKey = encodeURIComponent(property);
    var encodedValue = encodeURIComponent(cardDetails[property]);
    formBody.push(encodedKey + "=" + encodedValue);
  }
  formBody = formBody.join("&");

  return fetch(stripe_url + 'tokens', {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Bearer ' + secret_key
    },
    body: formBody
  });
};

This is an example of registering a credit card with stripe and getting the token. Similar implementations can be done for other API endpoints.

Rails 5 allows setting custom HTTP Headers for assets

This blog is part of our Rails 5 series.

Let’s look at by default what kind of response headers we get when we start with a brand new Rails 4.2.4 application.

header

Now let’s say that I want to set a custom response header. That’s easy. All I need to do is add following line of code in the controller.

response.headers['X-Tracking-ID'] = '123456'

Now I see this custom response header.

header

Setting custom response header for assets

Let’s say that I need that custom response header not only for standard web requests but also for my assets. For example application.js file is served by Rails in localhost. How would I set custom header to the asset being served by Rails here.

Actually that’s not possible in Rails 4. In Rails 4 we can set only one response header for assets that are served by Rails and that response header is Cache-Control.

Here is how I can configure Cache-Control for assets.

# open config/environments/production.rb and add following line
config.static_cache_control = 'public, max-age=1000'

Now we have modified ‘Cache-Control` header for the assets.

header

Besides Cache-Control no other response header can be set for assets served by Rails. That’s a limitation.

How Rails Apps lived with this limitation so far

Rails is not the best server to serve static assets. Apace and NGINX are much better at this job. Hence ,in reality, in production almost everyone puts either Apache or NGINX in front of a Rails server and in this way Rails does not have to serve static files.

Havig said that, Rails applications hosted at Heroku is an exception. Assets for Rails applications running at Heroku are served by Rails application itself.

Problem we ran into

Our website is hosted at heroku. When we ran Google page speed insights for our website we were warned that we were not using Expires header for the assets.

PageSpeed Insights Warning

Here are how the header looked for application.js.

PageSpeed Insights Warning

Now you see the problem we are running into.

  • Our application is hosted at Heroku.
  • Heroku lets Rails serve the assets.
  • Google page speed insights wants us to set Expires header to the assets.
  • Rails application allows only one header for the assets and that is ‘Cache-Control`.

One easy solution is to host our website at Digital Ocean and then use Apache or NGINX.

Rails 5 saves the day

Recently Rails merged basic support for access control headers and added ability to define custom HTTP Headers on assets served by Rails.

Behind the scenes, Rails uses ActionDispatch::Static middleware to take care of serving assets. For example, a request to fetch an image, goes through ActionDispatch::Static in the request cycle. ActionDispatch::Static takes care of serving Rack::File object from server with appropriate headers set in the response. The served image can have headers like Content-Type, Cache-Control.

Start using Rails master

To fix this, we first pointed the App to use Rails master.

gem 'rails', github: 'rails/rails'
gem 'rack', github: 'rack/rack' # Rails depends on Rack 2
gem 'arel', github: 'rails/arel' # Rails master works alongside of arel master.

Next, we changed asset configuration to start providing and using missing header for Expires.

# production.rb

config.public_file_server.headers = {
  'Cache-Control' => 'public, s-maxage=31536000, max-age=15552000',
  'Expires' => "#{1.year.from_now.to_formatted_s(:rfc822)}"
}

Here, we are first setting the Cache-Control header to use public (intermediate) caching, for a year (31536000 seconds) with max-age and s-maxage. Here s-maxage stands for Surrogate cache, which is used to cache internally by Fastly.

We then provide the missing Expires value with some future date in Internet formatted time value.

With this setup, we can see PageSpeed pickups the new headers on assets and does not warn us for the missing header.

PageSpeed Insights Warning

Here is the changed response header for asset.

PageSpeed Insights Warning

Further Reading

For better use and more details about different headers to use for the assets, please refer to RFC 2616.

Getting around Apple iTunesConnect account activation issue

It’s now 5 days since I talked to Apple support team and showed to them problem I was facing with activating my iTunesConnect account. So far I have not received any response from Apple.

And it’s not just me. A lot more people are facing the issue.

I’m sure one day Apple will fix this issue. In the meantime I’m posting how I got around this problem.

Migrating Rails app from postgresql to sql server

We started development on a project with PostgreSQL as our database. However midway we had to switch to SQL Server for a variety of reasons.

Here are some of the issues we noticed while migrating to SQL Server.

Unique constraint on a column which has multiple NULL values

As per the ANSI SQL standard unique constraint should allow multiple NULL values.

PostgreSQL documentation on unique constraint states following.

In general, a unique constraint is violated when there is more than one row in
the table where the values of all of the columns included in the constraint are
equal.

However, two null values are not considered equal in this comparison.

That means even in the presence of a unique constraint it is possible to store
duplicate rows that contain a null value in at least one of the constrained
columns.

This behavior conforms to the SQL standard, but we have heard that
other SQL databases might not follow this rule. So be careful when developing
applications that are intended to be portable.

In SQL Server a unique constraint does not allow multiple NULL values.

Devise by default adds unique index on reset_password_token column.

add_index :users, :reset_password_token, :unique => true

Devise is doing the right thing by enforcing a unique index on reset_password_token so that when a user clicks on a link to reset password the application would know who the user is.

However here is the problem. If we add a new user then by default the value of reset_password_token is NULL. If we add another user then we have two records with NULL value in reset_password_token. This works in PostgreSQL.

But SQL Server would not allow to have two records with NULL in reset_password_token column.

So how do we solve this problem.

Partial index to rescue. It is also known as Filtered index. Both PostgreSQL and SQL server support it. Rails also supports partial index by allowing us to pass where option as shown below.

add_index :users, :reset_password_token,
                  unique: true,
                  where: 'reset_password_token IS NOT NULL'

Please visit this issue if you want to see detailed discussion on this topic.

This behavior of SQL Server comes in play in various forms. Let’s say that we are adding api_auth_token to an existing users table.

Typically a migration for that might look like as shown below.

add_column :users, :api_auth_token, :string,
                                    :null => true,
                                    :unique => true

In this case we have plenty of records in the users table so the above migration will fail in PostgreSQL. We will have to resort to usage of partial index to fix this issue.

Adding not null constraint on a column with an index

In PostgreSQL following case will work just fine.

add_column :users, :email, :string, :unique => true
change_column :users, :email, :null => false

Above migration will fail with SQL Server.

In SQL Server a “not null constraint” cannot be added on a column which has a index on it. We need to first remove the unique index, then add the “not null” constraint and then add the unique index back.

The other solution is to add not NULL constraint first in the migration and then add any index.

Serialize array into a string column

ActiveRecord supports Array Datatype for PostgreSQL. We were using this feature to store a list of IDs.

After switching to SQL server we converted the column into string type and serialized the array.

serialize :user_ids, Array

Configuring Pycharm IDE to run a Robot Framework test suite or a single test script

Pycharm is a convenient IDE to work with Robot framework. To run a test suite or a test script, one can do so only through console. Running tests through console is very demanding. If user can run tests from Pycharm itself then that helps improve productivity. This blog explains how to configure Pycharm to be able to run test suite or a single test from the IDE itself.

Configuration to run a single test script

pycharm robot 1 pycharm robot 2 pycharm robot 3

Running a single test script

pycharm robot 4

Configuration to run a particular test suite

pycharm robot 5

Running a particular test suite

pycharm robot 6

Optimize JavaScript code using BabelJS

Though Babel is a transpiler to convert ESNext code to ES5, it can be used to optimize the code as well.

Let’s say we want to convert following ES6 code using Babel.

let a = 10;
let b = 42;

if (a < b) {
  console.log("a is less than b");
} else {
  console.log("b is less than a");
}

It will get translated to:

"use strict";

var a = 10;
var b = 42;

if (a < b) {
  console.log("a is less than b");
} else {
  console.log("b is less than a");
}

All good so far. Let’s try Babel’s constant folding plugin. I am compiling the ES6 code from command line this time.

babel --plugins constant-folding index.js --out-file bundle.js -w

This gives us following output:

"use strict";

var a = 10;
var b = 42;

if (true) {
  console.log("a is less than b");
} else {
  console.log("b is less than a");
}

If condition changed from (a < b) to (true). The constant-folding plugin has smartly evaluated the conditional expression a < b and replaced the code with the result of that expression.

This plugin can also optimize other expressions as shown below.

// Unary operators
console.log(!true);

// Binary expression
console.log(20 + 22);

// Function calls
console.log(Math.min(91, 2 + 20));

Which gets optimized to:

// Unary operators
console.log(false);

// Binary expression
console.log(42);

// Function calls
console.log(22);

How does this actually work?

Though we are using a “constant folding plugin” to achieve this optimization, the real work happens in Babel itself.

For every expression in the code, the constant folding plugin calls evaluate function from Babel source code. This function checks whether it can confidently find end value for a given expression.

The evaluate function returns confidence level and end value for any given expression. Based on this “confidence level”, constant folding plugin replaces the expression with their end values altering our original code as follows.

How evaluate handles different cases

For code Math.min(10, 20), evaluate will return

{ confident: true, value: 10 }

For code a < b, evaluate will return

{ confident: true, value: true }.

But for user defined function like foo('bar') or browser defined console.log('hello'), evaluate will return

{ confident: false, value: undefined }.

In the above case “confident” value will be “false” even if function returns a constant value. For example for code foo(100), evaluate will return

{ confident: false, value: undefined }.

In the above case function foo will always return 100. Still Babel has low confidence level. Why? That’s because Babel sees that it is a function and it bails out. It does not even look inside to try to figure things out.

Here is evaluate code in Babel. You should check it out.

How much optimization is possible?

How much help we will get from Babel for optimizing our code? Will it optimize everything?

The answer is unfortunately no.

As of now, Babel optimizes logical, binary, conditional expressions. It can also evaluate function calls on literals like "babel".length confidently if the literal is string or number.

For function calls, it supports only certain callees like String, Number and Math. So call to a user defined function, even if it’s returning a fixed value, will not be optimized.

Experimental feature

This feature looks great. But it’s available as experimental feature. If you use the plugin you will get following warning. unless you enable experimental flag.

$ babel --plugins constant-folding index.js --out-file bundle.js -w

[BABEL] index.js: THE TRANSFORMER constant-folding HAS BEEN MARKED AS EXPERIMENTAL AND IS WIP. USE AT YOUR OWN RISK. THIS WILL HIGHLY LIKELY BREAK YOUR CODE SO USE WITH **EXTREME** CAUTION. ENABLE THE `experimental` OPTION TO IGNORE THIS WARNING.

In order to get rid of warning you need to pass --experimental flag like this.

$ babel --plugins constant-folding index.js --out-file bundle.js -w
--experimental

Eliminating dead code

In above code example, we know that the result of if (a < b) is true based on values of a and b. Since the result is not going to change no matter what there is no need to have the if and else clauses.

That’s dead code.

Can Babel help us eliminate dead code?

Yes with the help of minification.deadCodeElimination option.

babel --optional minification.deadCodeElimination index.js --out-file bundle.js -w

Which converts earlier code to:

"use strict";

console.log("a is less than b");

I will talk about how Babel can eliminate dead code in a later post.

How to test React Native App on a real iPhone

I have been developing a new iOS app using React Native. I have been testing it using simulator provided by Xcode. Now it’s time to test the app using a real device. One could ask why test on a real device if it works perfectly on a simulator. Here are some of the reasons.

  • There are a number of device specific features which are not testable on a simulator. Phone calls, camera, gps data, compass and vibration are a few of them.
  • Testing unexpected cases that can only be tested on a real device. Like how your application handles incoming calls, low memory situations, low disk space, limited data connectivity etc.
  • Hardware-wise, your device is different than your Mac. If your app is graphics intensive and requires a lot of CPU usage, it might work seamlessly on your simulator depending on your Mac’s specifications. But it might be laggy and glitchy on the real device.

Now let’s look into how you can start testing your React Native app on an real iPhone.

Step 1 - Plug in your device

Plug in your device to your Mac and open Xcode. You will be able to select your device to the right of the Play and Stop buttons.

select device

You might run into one of the following two errors if you have not enrolled into Apple’s Developer Program.

Error 1 : Failed to code sign

xcode error 1

xcode error 2

To fix above issues please enroll in Apple Developer program.

Error 2 : Disk Image could not be mounted

The Developer Disk Image could not be mounted :
You may be running a version of iOS that is not supported by this version of XCode

could not mount

This can happen if your iOS version is not supported by your current version of Xcode. To fix this, just update your Xcode to the latest version from the App Store.

Step 2 - Set right deployment target

In your Xcode project setup the Deployment Target should be set to less than or equal to the iOS version installed on the device.

If your iPhone is running iOS 7.0 and you have set “Deployment Target” as 8.0 then the app will not work. If your iPhone is running iOS 8.0 and you have set “Deployment Target” as 7.0 then the app will work.

deployment target

Step 3 - Fix “Could not connect to development server” error

So the app is installed and you can see the launch screen. That’s great. But soon you might get following error on your iPhone.

Could not connect to development server.
Ensure node server is running and available on the same
network – run ‘npm start’ from react-native root.

<img src=”/assets/testing_ios_app/connection-error-63965bcfef9be98b91e5fa920a701c0f4e556733d179ca18d00c34f31f3a7970.PNG” alt=”connection error” width=200 height=350 width=”640” height=”1136”>

To fix this open AppDelegate.m file in your project’s iOS folder.

Locate line mentioned below and replace localhost with your Mac IP address e.g. 192.168.x.x.

To find the ip address of your Mac this is what ReactNative suggests us to do.

you can get ip by typing ifconfig into the terminal and selecting the * inet value under en0:.

jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];

Save and click run again. This will fix the error.

Step 3 - Fix connecting to API hosted on local development server

Now the app is installed and you can navigate through the app screens. If the app attempts to make API call to the server running locally on the machine then depending on how the local server was started it could be a problem.

In my case, I have a Ruby on Rails application running on my local machine. I had started my rails server by executing command rails server.

To do this, the app should be able to access the rails server using the private ip of the server e.g. 192.168.x.x:3000. Turned out that I had started my rails server using command rails server.

Becase of change in Rails 4.2 rails server listens to localhost and not 0.0.0.0.

The rails guide further says following.

with this change you will no longer be able to access the Rails server from a different machine, for example if your development environment is in a virtual machine and you would like to access it from the host machine. In such cases, please start the server with rails server -b 0.0.0.0 to restore the old behavior.

In this case iPhone is trying to talk to Rails server so Rails server must be started using following command.

rails server -b 0.0.0.0
or
rails server --binding=0.0.0.0

By doing so, now you can connect to your Rails app from your local network, by browsing to http://192.168.x.x:3000.

Summary

These were some of the issues I came across while testing my iOS app on an actual device and how I fixed them. Hopefully, this blog post helps you fix these error cases get you started on testing quickly.

Using ReactJS with Rails Action Cable

Recent DHH, announced availability of alpha version of Action Cable.

Action Cable is still under heavy development but it comes with examples to demonstrate its usage.

Action Cable integrates websocket based real-time communication in Ruby on Rails applications. It allows building realtime applications like Chats, Status updates, etc.

Action Cable + React

Action Cable provides real time communication. ReactJS is a good tool to manage view complexity on the client side. Together they make it easy to develop snappy web applications which requires state management on the client side without too much work.

Anytime data changes the new data is instantly provided by Action Cable and the new data is shown on the view without user doing anything on the application by ReactJS.

Integrating React

The official Action Cable Example is a chat application. We will be building the same application using ReactJS.

First follow the instructions mentioned to get a working chat application using Action Cable.

Now that the chat application is working let’s get started with adding ReactJS to the application.

Please note that we have also posted a number of videos on learning ReactJS. Check them out if you are interested.

Step 1 - Add required gems to Gemfile

# react-rails isn't compatible yet with latest Sprockets.
# https://github.com/reactjs/react-rails/pull/322
gem 'react-rails', github: 'vipulnsward/react-rails', branch: 'sprockets-3-compat'

# Add support to use es6 based on top of babel, instead of using coffeescript
gem 'sprockets-es6'

Step 2 - Add required JavaScript files

Follow react-rails installation and run rails g react:install.

This will

  • create a components.js file.
  • create app/assets/javascripts/components/ directory.

Now put following lines in your application.js:

//= require react
//= require react_ujs
//= require components

Make sure your app/assets/javascripts/application.js looks like this

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react
//= require react_ujs
//= require components
//= require cable

//= require channels
//= require_tree .

Step 3 - Setup Action Cable to start listening to events

We will be using es6, so lets replace the file app/assets/javascripts/channels/index.coffee, with app/assets/javascripts/channels/index.es6 and add following code.

var App = {};
App.cable = Cable.createConsumer('ws://localhost:28080');

Also remove file app/assets/javascripts/channels/comments.coffee, which is used to setup subscription. We will be doing this setup from our React Component.

Step 4 - Create CommentList React Component

Add following code to app/assets/javascripts/components/comments_list.js.jsx.

var CommentList = React.createClass({
  getInitialState(){
    let message = JSON.parse(this.props.message);
    return {message: message};
  },

  render() {
    let comments = this.state.message.comments.map((comment) => {
      return this.renderComment(comment);
    });

    return (
      <div>{comments}</div>
    );
  },

  renderComment(comment) {
    return (
      <article key={comment.id}>
        <h3>Comment by { comment.user.name }</h3>
        <p>{ comment.content }</p>
      </article>
    );
  }
});

Here we have defined a simple component to display a list of comments associated with a message. Message and associated comments are passed as props.

Step 5 - Create message JSON builder

Next we need to setup data needed to be passed to the component.

Add following code to app/views/messages/_message.json.jbuilder.

json.(message, :created_at, :updated_at, :title, :content, :id)
json.comments(message.comments) do |comment|
  json.extract! comment, :id, :content
  json.user do
    json.extract! comment.user, :id, :name
  end
end

This would push JSON data to our CommentList component.

Step 6 - Create Rails Views to display component

We now need to setup our views for Message and display of Comments.

We need form to create new Comments on messages. This already exists in app/views/comments/_new.html.erb and we will use it as is.

<%= form_for [ message, Comment.new ], remote: true do |form| %>
  <%= form.text_area :content, size: '100x20' %><br>
  <%= form.submit 'Post comment' %>
<% end %>

After creating comment we need to replace current form with new form, following view takes care of that.

From the file app/views/comments/create.js.erb delete the line containing following code. Please note that below line needs to be deleted.

$('#comments').append('<%=j render @comment %>');

We need to display the message details and render our component to display comments. Insert following code in app/views/messages/show.html.erb just before <%= render 'comments/comments', message: @message %>

<%= react_component 'CommentList', message: render(partial: 'messages/message.json', locals: {message: @message}) %>

After inserting the code would look like this.

<h1><%= @message.title %></h1>
<p><%= @message.content %></p>
<%= react_component 'CommentList', message: render(partial: 'messages/message.json', locals: {message: @message}) %>
<%= render 'comments/new', message: @message %>

Notice how we are rendering CommentList, based on Message json content from jbuilder view we created.

Step 7 - Setup Subscription to listen to Action Cable from React Component

To listen to new updates to comments, we need to setup subscription from Action Cable.

Add following code to CommentList component.

setupSubscription(){

  App.comments = App.cable.subscriptions.create("CommentsChannel", {
    message_id: this.state.message.id,

    connected: function () {
      setTimeout(() => this.perform('follow',
                                    { message_id: this.message_id}), 1000 );
    },

    received: function (data) {
      this.updateCommentList(data.comment);
    },

    updateCommentList: this.updateCommentList

    });
}

We need to also setup related AC Channel code on Rails end.

Make following code exists in app/channels/comments_channel.rb

class CommentsChannel < ApplicationCable::Channel
  def follow(data)
    stop_all_streams
    stream_from "messages:#{data['message_id'].to_i}:comments"
  end

  def unfollow
    stop_all_streams
  end
end

In our React Component, we use App.cable.subscriptions.create to create a new subscription for updates, and pass the channel we want to listen to. It accepts following methods for callback hooks.

  • connected: Subscription was connected successfully. Here we use perform method to call related action, and pass data to the method. perform('follow', {message_id: this.message_id}), 1000), calls CommentsChannel#follow(data).

  • received: We received new data notification from Rails. Here we take action to update our Component. We have passed updateCommentList: this.updateCommentList, which is a Component method that is called with data received from Rails.

Complete React Component

Here’s how our complete Component looks like.

var CommentList = React.createClass({
  getInitialState(){
    let message = JSON.parse(this.props.message);
    return {message: message};
  },

  render() {
    let comments = this.state.message.comments.map((comment) => {
      return this.renderComment(comment);
    });

    return (
        <div>{comments}</div>
    );
  },

  renderComment(comment) {
    return (
        <article key={comment.id}>
          <h3>Comment by { comment.user.name } </h3>
          <p>{ comment.content }</p>
        </article>
    );
  },

  componentDidMount() {
    this.setupSubscription();
  },

  updateCommentList(comment) {
    let message = JSON.parse(comment);
    this.setState({message: message});
  },

  setupSubscription() {

    App.comments = App.cable.subscriptions.create("CommentsChannel", {
      message_id: this.state.message.id,

      connected: function () {
        // Timeout here is needed to make sure Subscription
        // is setup properly, before we do any actions.
        setTimeout(() => this.perform('follow',
                                      {message_id: this.message_id}),
                                      1000);
      },

      received: function(data) {
        this.updateCommentList(data.comment);
      },

      updateCommentList: this.updateCommentList
    });
  }
});

Step 7 - Broadcast message when a new comment is created.

Our final piece is to broadcast new updates to message to the listeners, that have subscribed to the channel.

Add following code to app/jobs/message_relay_job.rb

class MessageRelayJob < ApplicationJob
  def perform(message)
    comment =  MessagesController.render(partial: 'messages/message',
                                         locals: {message: message})
    ActionCable.server.broadcast "messages:#{message.id}:comments",
                                 comment: comment
  end
end

which is then called from Comment model, like so-

Add this line to Comment model file app/model/comment.rb

after_commit { MessageRelayJob.perform_later(self.message) }

We are using message relay here, and will be getting rid of existing comment relay file - app/jobs/comment_relay_job.rb. We will also remove reference to CommentRelayJob from Comment model, since after_commit it now calls the MessageRelayJob.

Summary

Hopefully we have shown that Action Cable is going to be a good friend of ReactJS in future. Only time will tell.

Complete working example for Action Cable + ReactJS can be found here.

Verifying PubSub Services from Rails using Redis

Let’s say that we have a Service that reads and writes to Redis. We have BaseRedisService for managing connection, RedisWriterService to write to Redis and RedisReaderService to read from Redis.

require 'redis'

# Base class to manage connection
class BaseRedisService
 REDIS_HOST = '127.0.0.1'

 def connection
   if !(defined?(@@connection) && @@connection)
     @@connection =  Redis.new({ host: REDIS_HOST })
   end
   @@connection
 end

end
# Class to write to Redis
class RedisWriterService <  BaseRedisService
 attr_reader :key, :value

 def initialize key, value
   @key, @value = key, value
 end

 def process
   connection.set key, value
 end

end
# Class to read from Redis
class RedisReaderService < BaseRedisService
attr_reader :key

def initialize key
  @key = key
end

def process
  connection.get key
end

end

A test for the above mentioned case might look like this.

require 'test_helper'

class RedisPubSubServiceTest < ActiveSupport::TestCase

def test_writing_and_reading_value_using_redis
  value = 'Vipul A M'

  RedisWriterService.new('name', value).process
  assert_equal value, RedisReaderService.new('name').process
end

end

But now, we need to add PubSub to the service and verify that the service sends proper messages to Redis. For verifying from such a service, the service would need to listen to messages sent to Redis. Problem is that Redis listens in a loop. We would need to explicitly release control from listening and allow our tests to go ahead and verify some scenario.

Lets look at how these services would look.

class RedisPublisherService < BaseRedisService
attr_reader :options, :channel

def initialize channel, options
  @channel     = channel
  @options = options
end

def process
  connection.publish(options, channel)
end

end

and our Subscriber looks like this.

class RedisSubscriberService < BaseRedisService
attr_reader :channel

def initialize channel
  @channel = channel
end

def process
  connection.subscribe(channel) do |on|
    on.message do |channel, message|
      puts message
    end
  end
end

end

Notice that we don’t have control over returning value from the loop easily. Right now we just print on receiving a new message.

Now, lets start persisting our messages to some array in our Service. Also we will start exposing this from a thread variable so that it could be accessed from outside of execution of this listen loop.

class RedisSubscriberService < BaseRedisService
attr_reader :channel, :messages, :messages_count

def initialize channel, messages_count = 5
  @channel        = channel
  @messages       = []
  @messages_count = messages_count
end

def process
  connection.subscribe(channel) do |on|
    on.message do |channel, message|
      messages.unshift message
      Thread.current[:messages] = messages
    end
  end
end

end

We now have a way to access message state from the service to read any messages received by it. Lets say we define a new SubscriberService from a Thread, we could read messages like this.

subscriber = Thread.new { RedisSubscriberService.new('payment_alerts').process }
# Print first message from messages received
puts subscriber[:messages].first

Armed with this, we can now define a set of Rails helpers to use in our Rails tests.

module SubscriberHelpers
THREAD_PROCESS_TIMEOUT = 0.5

def setup_subscriber channel = 'test_channel'
  @subscriber = Thread.new { RedisSubscriberService.new(channel).process }
end

def teardown_subscriber
  @subscriber.kill
end

def with_subscriber
  yield
  @subscriber.join THREAD_PROCESS_TIMEOUT
end

def message_from_subscription
  @subscriber[:messages].first
end
end

Notice the with_subscriber method. It executes some code passed to it, then passes method execution to the subscriber process to read any messages sent and store onto messages store.

The count of the variable THREAD_PROCESS_TIMEOUT, can be experimented to set to a value that suites the system that’s being verified.

In our tests, we can now verify PubSub as-

require 'test_helper'

class RedisPubSubServiceTest < ActiveSupport::TestCase
include SubscriberHelpers

def setup
  setup_subscriber
end

def teardown
  teardown_subscriber
end

def test_writing_and_reading_back_values_from_pub_sub
  value = 'Vipul A M'

  with_subscriber do
    RedisPublisherService.new('test_channel', value).process
  end

  assert_equal value, message_from_subscription
end
end

Summary

We took a look at how PubSub based services can be verified by using threads and exposing messages from them, for verification. These can be tailored to support any similar PubSub service like Redis, and can be used to easily verify values being published from our services from Rails tests.

Voice based phone verification using twilio

In my previous blog post, I talked about how to do phone verification using SMS and now in this blog post I’m going to talk about how to do voice based phone verification using Twilio.

Requirement

Let’s change the requirement a bit this time.

  • After the user signs up, send an SMS verification. If SMS verification goes well then use that phone number for future use.
  • But if the user’s phone number doesn’t support the SMS feature, then call on user’s phone number for the verification.
  • In the call, ask the user to press 1 from keypad to complete the verification. If that user presses the 1 key, then mark the phone number as verified.

Step 1: Make a call for phone verification

We already handled SMS verification, so let’s add call related changes in PhoneVerificationService class.

class PhoneVerificationService
  attr_reader :user, :verification_through

  VERIFICATION_THROUGH_SMS  = :sms
  VERIFICATION_THROUGH_CALL = :call

  def initialize options
    @user                 = User.find(options[:user_id])
    @verification_through = options[:verification_through] || VERIFICATION_THROUGH_SMS
  end

  def process
    if verification_through == VERIFICATION_THROUGH_SMS
      perform_sms_verification
    else
      make_call
    end
  end

  private

  def from
    #phone number given by twilio
    Settings.twilio_number_for_app
  end

  def to
    "+1#{user.phone_number}"
  end

  def body
    "Please reply with this code '#{user.phone_verification_code}'" <<
    "to verify your phone number"
  end

  def send_sms
    Rails.logger.info "SMS: From: #{from} To: #{to} Body: \"#{body}\""

    twilio_client.account.messages.create ( from: from, to: to, body: body)
  end

  def make_call
    Rails.logger.info "Call: From: #{from} To: #{to}"

    twilio_client.account.calls.create( from: from, to: to, url: callback_url)
  end

  def perform_sms_verification
    begin
      send_sms
    rescue Twilio::REST::RequestError => e
      return make_call if e.message.include?('is not a mobile number')
      raise e.message
    end
  end

  def callback_url
    Rails.application.routes.url_helpers
      .phone_verifications_voice_url(host: Settings.app_host,
                                     verification_code: user.phone_verification_code)
  end

  def twilio_client
    @twilio ||= Twilio::REST::Client.new(Settings.twilio_account_sid,
                                         Settings.twilio_auth_token)
  end
end

In PhoneVerificationService class we have added some major changes:

  1. We have defined one more attribute reader verification_through and in initialize method we have set it.
  2. We have created two new constants VERIFICATION_THROUGH_SMS & VERIFICATION_THROUGH_CALL.
  3. We have changed process method and now we check which verification process should be taken place based on verification_through attribute.
  4. We also have added new methods perform_sms_verification, make_call and callback_url.

Let’s go through these newly added methods.

perform_sms_verification:

In this method, first we try to send an SMS verification. If SMS verification fails with error message like ‘is not a mobile number’ then in the rescue block, we make a phone verification call or we raise the error.

make_call:

In this method, we create an actual phone call and pass the all required info to twilio client object.

callback_url:

In this method, we set the callback_url which is required for Twilio for making a call. When we call the user for verification, our app needs to behave like a human and should ask to the user to press 1 to complete the verification (i.e. In the form of TwiML). This callback_url needs be to set in our app.

Step 2: Add voice action in phone verification controller

For callback_url, add route for voice action in config/routes.rb

post 'phone_verifications/voice' => 'phone_verifications#voice'

Add voice action and required code for it in PhoneVerificationsController.

class PhoneVerificationsController < ApplicationController
  skip_before_filter :verify_authenticity_token
  after_filter :set_header

  HUMAN_VOICE = 'alice'

  def voice
    verification_code = params[:verification_code]

    response = Twilio::TwiML::Response.new do |r|
      r.Gather numDigits: '1',
               action: "/phone_verifications/verify_from_voice?verification_code=#{verification_code}",
               method: 'post' do |g|

        g.Say 'Press 1 to verify your phone number.', voice: HUMAN_VOICE
      end
    end

    render_twiml response
  end

  def verify_from_message
    user = get_user_for_phone_verification
    user.mark_phone_as_verified! if user

    render nothing: true
  end

  private

  def get_user_for_phone_verification
    phone_verification_code = params['Body'].try(:strip)
    phone_number            = params['From'].gsub('+1', '')

    condition = { phone_verification_code: phone_verification_code,
                  phone_number: phone_number }

    User.unverified_phones.where(condition).first
  end

  def set_header
    response.headers["Content-Type"] = "text/xml"
  end

  def render_twiml(response)
    render text: response.text
  end
end

In this voice method, we have set up the Twilio response. When a call is made to the user, this response will get converted into robotic human voice. render_twiml method which sets twilio response in text form is required for Twilio APIs. Set up the response header in the set_header method which gets called in after_filter method.

Step 3: Set request URL for voice phone verification in Twilio

In voice action method, we have setup the request url in the action key of Twilio response object, that also needs to be set in your Twilio account. So when, user replies back to the call query, Twilio will make a request to our app and adds its own some values as parameters to the request. Using those parameters we handle the actual phone verification in the app.

Open twilio account and under NUMBERS section/tab, click on your Twilio number. Then in Voice section, add request URL with HTTP POST method. Add URL like this.

http://your.ngrok.com/phone_verifications/verify_from_voice/

We need Ngrok to expose local url to external world. Read more about it in my previous blog post.

Step 4: Add verify_from_voice action in phone verification controller

First add route for this action in config/routes.rb

post "phone_verifications/verify_from_voice" => "phone_verifications#verify_from_voice

Add this method, in your PhoneVerificationsController.

  def verify_from_voice
    response = Twilio::TwiML::Response.new do |r|
      if params['Digits'] == "1"
        user = get_user_for_phone_verification
        user.mark_phone_as_verified!

        r.Say 'Thank you. Your phone number has been verified successfully.',
               voice: HUMAN_VOICE
      else
        r.Say 'Sorry. Your phone number has not verified.',
               voice: HUMAN_VOICE
      end
    end

    render_twiml response
  end

Modify private method get_user_for_phone_verification to support voice verification in PhoneVerificationsController.

  def get_user_for_phone_verification
    if params['Called'].present?
      phone_verification_code = params['verification_code']
      phone_number            = params['To']
    else
      phone_verification_code = params['Body'].try(:strip)
      phone_number            = params['From']
    end
    condition = { phone_verification_code: phone_verification_code,
                  phone_number: phone_number.gsub('+1', '') }

    User.unverified_phones.where(condition).first
  end

In the verify_from_voice method, we get parameters Digits, To & verification_code from Twilio request. Using these parameters, we search for user in the database. If we get the proper user then we mark user’s phone number as verified phone number.

Gotcha with after_commit callback in Rails

after_commit callback in Rails is triggered after the end of transaction.

For eg. I have a Post model for which the number of lines of the content are calculated in the after_commit callback:

class Post < ActiveRecord::Base
  after_commit :calculate_total_lines, if: -> (post) { post.previous_changes.include?(:content) }

  def calculate_total_lines
    update! total_lines: content.split("\n").length
  end
end
post = Post.create! content: "Lets discuss Rails 5.\n", author: 'Prathamesh'
assert_equal 1, post.total_lines

Now lets wrap the creation of post inside a transaction block:

Post.transaction do
  post = Post.create! content: "Lets discuss Rails 5.\n", author: 'Prathamesh'
  assert_equal 1, post.total_lines
end

The test will fail now.

#   1) Failure:
# BugTest#test_within_transaction [after_commit_test.rb:45]:
# Expected: 1
#   Actual: nil

Why? Lets recall. after_commit callback will get executed after the end of transaction.

So until all the code inside transaction is completed, the callback is not going to get executed.

Here is a gist with complete test.

Next time you are using an after_commit callback and a transaction, make sure that code inside the transaction is not dependent on the result of the callback.

Blue border around JWPLAYER video

Latest versions of JWPlayer(6.9 onwards) adds blue border around the video when it is in focus.

JWPlayer blue border

This is because of the CSS class jwplayer-tab-focus.

The blue border around currently selected video allows to identify which instance of JWPlayer is in focus.

But with a single JWPlayer instance, it can be annoying.

To remove this blue border, we can override the default JWPlayer CSS as follows.

.jw-tab-focus:focus {
    outline: none;
}

To keep all the overridden CSS in once place, we can add this change in a separate file such as jwplayer_overrides.css.

Phone verification using SMS via Twilio

In this blog post, I’m going to show you how to do phone verification using SMS via Twilio. We will be using Twilio gem.

Requirement

  • When a user signs up , we want to send an SMS to that user with a random string to verify user’s phone number.
  • If that user replies back with that code, then verify user’s phone number in the app. Once the phone number is verified, then we can use that phone number for future use.

Step 1: Create required columns in users table

Let’s create phone_number, phone_verification_code and phone_verified columns in the users table.

 $ bin/rails generate migration AddPhoneAttributesToUsers phone_number:string phone_verification_code:string phone_verified:boolean

Then run the migration.

Step 2: Add phone number field in registration form

Add phone_number field in the registration form.

  <%= f.text_field :phone_number %>

Step 3: Send an SMS with verification code

When a user submits registration form, we need to send SMS if phone number is present. To handle this, add following code in User model.

class User < ActiveRecord::Base
  scope :unverified_phones,  -> { where(phone_verified: false) }

  before_save :set_phone_attributes, if: :phone_verification_needed?
  after_save :send_sms_for_phone_verification, if: :phone_verification_needed?

  def mark_phone_as_verified!
    update!(phone_verified: true, phone_verification_code: nil)
  end

  private

  def set_phone_attributes
    self.phone_verified = false
    self.phone_verification_code = generate_phone_verification_code

    # removes all white spaces, hyphens, and parenthesis
    self.phone_number.gsub!(/[\s\-\(\)]+/, '')
  end

  def send_sms_for_phone_verification
    PhoneVerificationService.new(user_id: id).process
  end

  def generate_phone_verification_code
    begin
     verification_code = SecureRandom.hex(3)
    end while self.class.exists?(phone_verification_code: verification_code)

    verification_code
  end

  def phone_verification_needed?
    phone_number.present? && phone_number_changed?
  end
end

We have added 2 major changes in the user model,

  • set_phone_attributes method is set in before_save callback.
  • send_sms_for_phone_verification method is set in after_save callback.

In set_phone_attributes method, we are setting up the phone attributes mainly sanitizing phone number and generating unique phone verification code. In send_sms_for_phone_verification method, we send SMS to the user. Creation of SMS for the phone verification message is handled in PhoneVerificationService class.

class PhoneVerificationService
  attr_reader :user

  def initialize(options)
    @user = User.find(options[:user_id])
  end

  def process
    send_sms
  end

  private

  def from
    # Add your twilio phone number (programmable phone number)
    Settings.twilio_number_for_app
  end

  def to
    # +1 is a country code for USA
    "+1#{user.phone_number}"
  end

  def body
    "Please reply with this code '#{user.phone_verification_code}' to
    verify your phone number"
  end

  def twilio_client
    # Pass your twilio account sid and auth token
    @twilio ||= Twilio::REST::Client.new(Settings.twilio_account_sid,
                                         Settings.twilio_auth_token)
  end

  def send_sms
    Rails.logger.info "SMS: From: #{from} To: #{to} Body: \"#{body}\""

    twilio_client.account.messages.create(
      from: from,
      to: to,
      body: body
    )
  end
end

In PhoneVerificationService class, we have defined user as an attribute reader and in initialize method, we have set the user object to it. Now if you see process method, it does lots of stuff for us.

Lets go through each method.

  • from - In this method, we set up the twilio phone number e.g. programmable number.
  • to - In this method, we set the phone number to which we want to send an SMS.
  • body - In this method, we build text message with verification code.
  • twilio_client - It creates twilio client based on twilio account sid and auth token.
  • send_sms - And last, it sends SMS to the user.

Step 4: Set request URL for phone verification in Twilio

As of now the system has the capability to send SMS to a user. Now we need to add capability to receive the SMS and to match the verification code.

First, we need to set up a request URL in Twilio account.

Open twilio account and under NUMBERS section/tab, click on your Twilio number. Then in Messaging section, add request URL with HTTP POST method. Add URL like this.

http://your.ngrok.com/phone_verifications/verify_from_message/

But to make it work, we need our Rails app on the public internet. There are two options for this:

  1. Deploy Rails app to your VPS or PaaS of choice.
  2. Use a tunneling service to take the server running on your development machine and make it available at an address on the public internet.

I’m going to use Ngrok tunneling service for the purpose of this blog. You can check this blog for more about its usage.

Step 5: Create phone verification controller

We need one more controller, which will handle phone verification when request comes from Twilio. When a user replies back with a verification code, it will trigger request URL through Twilio API. To handle that request, let’s add phone verifications controller.

  $ bin/rails generate controller phone_verifications

Add new route in config/routes.rb

post "phone_verifications/verify_from_message" => "phone_verifications#verify_from_message"

Add following code to the PhoneVerificationsController.

class PhoneVerificationsController < ApplicationController
  skip_before_action :verify_authenticity_token

  def verify_from_message
    user = get_user_for_phone_verification
    user.mark_phone_as_verified! if user

    render nothing: true
  end

  private

  def get_user_for_phone_verification
    phone_verification_code = params['Body'].try(:strip)
    phone_number            = params['From'].gsub('+1', '')

    condition = { phone_verification_code: phone_verification_code,
                  phone_number: phone_number }

    User.unverified_phones.where(condition).first
  end
end

In this controller, we added skip_before_action :verify_authenticity_token, this is because we need to allow twilio request in our Rails app which is actually an outside request (e.g. not secured request). This means we have disabled CSRF detection for this controller.

Now look at the verify_from_message method, in this method we take phone verification code and phone number from params hash. Using those data, we find the user from the database. Once we get the user, then we mark user’s phone number as a verified phone number.

Finally we are set to send business level text messages to the verified phone number.

This blog has more information about how to make secure twilio requests.

Author information in jekyll blog

BigBinary’s blog is powered by jekyll. In every blog we display author’s name, author’s twitter handle, author’s github id and author’s avatar. In this blog I’m going to discuss how we collect all that information in a simple manner.

We create a directory called _data in the root folder. This directory has a single file called authors.yml which in our case looks like this.

vipulnsward:
  name: Vipul
  avatar: http://bigbinary.com/assets/team/vipul.jpg
  github: vipulnsward
  twitter: vipulnsward
neerajdotname:
  name: Neeraj Singh
  avatar: http://bigbinary.com/assets/team/neeraj.jpg
  github: neerajdotname
  twitter: neerajdotname

We do not need to do anything to load authors.yml . It is automatically loaded by jekyll.

When we create a blog then the top of the blog looks like this.

---
layout: post
title: How to deploy jekyll site to heroku
categories: [Ruby]
author_github: neerajdotname
---

Notice the last line where we have put in the author’s github id. That’s the identifier we use to pull in author’s information.

In order to display author’s name we have following code in the layout.

<span class="author-name">
  {{ site.data.authors[page.author_github].name }}
</span>

Similary to display author’s twitter handle and github id we have following code.

<a href="www.twitter.com/{{site.data.authors[page.author_github].twitter}}">
  <i class="ico-twitter"></i>
</a>
<a href="www.github.com/{{site.data.authors[page.author_github].github}}">
  <i class="ico-github"></i>
</a>

Now the blog will display the author information and all this information is nicely centralized in one single file.

How to obtain current time from a different timezone in Selenium IDE using javascript

I had encountered a problem in one of our projects where it was required to obtain the current time from a different timezone and then use it. I am in IST (Indian Standard Timezone - 5.50) and was required to get the time in EST (Eastern Standard Timezone + 5.00)

These are the set of commands I used to achieve that.

Command : storeEval
Target  : var d = new Date();
          d.setTime(new Date( (d.getTime() + (d.getTimezoneOffset() * 60000))            + (3600000 * (-5) ) ));
          d.toLocaleTimeString();
Value   : timeEst

Command : echo
Target  : ${timeEst}
Value   :

storeEval command is used to store the value in the variable timeEst after evaluating the javascript code.

var d = new Date(); a new date object is created.

d.getTime() method returns the number of milliseconds between midnight of January 1, 1970 and the specified date (as is present in the variable “d”).

d.getTimezoneOffset() method returns the time difference between UTC (Coordinated Universal Time) time and local time from the variable “d”, in minutes. For example, If our time zone is GMT-5.50, -330 will be returned.

Since getTime() is in milliseconds and getTimezoneOffset() is in minutes; getTimezoneOffset() is multiplied with 60000 to make it into milliseconds.

The expression 3600000 * (- 5) is required to make the time from UTC to EST. The difference between UTC and EST is -5 hours. So, to make the hours to milliseconds we need to multiply with 3600000 (60 min x 60 sec x 1000 millisec).

d.setTime() method is used to set the time of variable “d” after evaluating the expression.

With the above, the variable “d” is set with the date and time of the EST time.

d.toLocaleTimeString() method returns the time portion of a Date object as a string, using locale conventions.

The time string obtained above is stored in the variable timeEst.

echo ${timeEst}, the time string is displayed in the console.


Using est time

Selenkum javascript EST time


Using est date

Selenkum javascript EST date