Configuring bundler using bundle config

Bundler helps in managing gem dependencies of ruby projects. You can specify which gems and versions you need, bundler will install them and load them at runtime. Bundler ensures that gems you need are present in the environment you need.

Bundle configurations

Bundler gets its configurations from local application (app/.bundle/config), environment variables and user’s home directory (~/.bundle/config) in the order of priority.

To list all bundler configurations for the current bundle, run bundle config without any parameters. You will also get the location where the value is set.

$ bundle config
Settings are listed in order of priority. The top value will be used.

You might see different result based on configuration of bundler on your machine.

To get value for the specific configuration setting, run bundle config with name.

$ bundle config disable_multisource
Settings for `disable_multisource` in order of priority. The top value will be used
You have not configured a value for `disable_multistore`

Setting Configuration

To set the value of the configuration setting, use bundle config with name and value. Configuration will be stored in ~/.bundle/config.

$ bundle config build.pg --with-pg-config=/opt/local/lib/postgresql91/bin/pg_config

$ bundle config
Settings are listed in order of priority. The top value will be used.
build.pg
Set for the current user (/Users/username/.bundle/config): "--with-pg-config=/opt/local/lib/postgresql91/bin/pg_config"

If any config already has a value, it will be overwritten directly and user will be warned.

$ bundle config build.pg --with-pg-config=/usr/pgsql-9.1/bin/pg_config
You are replacing the current global value of build.pg, which is currently "--with-pg-config=/opt/local/lib/postgresql91/bin/pg_config"

Application level configuration

By default setting configuration value will set it for all projects on the machine. You can set configurations specific to local application with --local option. This will store value in app/.bundle/config.

$ bundle config --local auto_install false
You are replacing the current local value of auto_install, which is currently nil

$ bundle config auto_install
Settings for `auto_install` in order of priority. The top value will be used
Set for your local app (/Users/username/Documents/Workspace/app-name/.bundle/config): "false"
Set for the current user (/Users/username/.bundle/config): "true"

You can run bundle config with --global. This will set values at global level i.e. across all applications on the machine. It will be similar to running bundle config without any options.

Deleting configuration

You can delete configuration with --delete option.

$ bundle config --delete auto_install
$ bundle config
Settings are listed in order of priority. The top value will be used.
disable_multisource
Set for the current user (/Users/username/.bundle/config): "true"

build.pg
Set for the current user (/Users/username/.bundle/config): "--with-pg-config=/usr/pgsql-9.1/bin/pg_config"

This is not compatible with --local and --global. This will delete configuration from local and global resources.

Build Options

You can pass the flags required for installing particular gem to bundler with bundle config.

Many El Capitan users face an issue while installing eventmachine gem. The issue can be resolved by providing path to OpenSSL include directory while installing eventmachine.

$ gem install eventmachine -v '1.0.8' -- --with-cppflags=-I/usr/local/opt/openssl/include

As location of configuration will vary from machine to machine, we can set this with bundle config.

$ bundle config build.eventmachine --with-cppflags=-I/usr/local/opt/openssl/include

Now bundler will pick this configuration while installing eventmachine gem.

Configuration keys

Various configuration keys are available with bundler. These keys are available in two forms. You can specify them in canonical form with bundle config or set them in environment variable form. Following are canonical forms and their usage. Corresponding environment variables are specified in bracket.

auto_install

Setting auto_install config will enable automatic installing of gems instead of raising an error. This applies to show, binstubs, outdated, exec, open, console, license, clean commands.

Example, When you try to run bundle show for the gem which is not yet installed you will get an error.

$ bundle show pg
Could not find gem 'pg'.

You can set auto_install to remove this error and install gem.

$ bundle config auto_install true

$ bundle show pg
# Gem will get installed
/Users/username/.rvm/gems/ruby-2.2.2@gemset-auto/gems/pg-0.17.1

path (BUNDLE_PATH)

You can specify location to install your gems. Default path is $GEM_HOME for development and vendor/bundle when –deployment is used.

$ bundle config path NEW_PATH
$ bundle install
# Gems will get installed
#
#
Bundle complete! 4 Gemfile dependencies, 35 gems now installed.
Bundled gems are installed into NEW_PATH.

frozen (BUNDLE_FROZEN)

You can freeze changes to your Gemfile.

$ bundle config frozen true

If frozen is set and you try to run bundle install with changed Gemfile, you will get following warning.

You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.

If this is a development machine, remove the /Users/username/Documents/Workspace/app-name/Gemfile freeze
by running `bundle install --no-deployment`.

You have added to the Gemfile:
* minitest-reporters

without (BUNDLE_WITHOUT)

You can skip installing groups of gems with bundle install. Specify : separated group names whose gems bundler should not install.

$ bundle config --local without development:test

$ bundle install
# This will install gems skipping development and test group gems.

bin (BUNDLE_BIN)

You can set the directory to install executables from gems in the bundle.

$ bundle config bin NEW_PATH

$ bundle install
# This will install executables in NEW_PATH

gemfile (BUNDLE_GEMFILE)

You can set the file which bundler should use as theGemfile. By default, bundler will use Gemfile. The location of this file also sets the root of the project, which is used to resolve relative paths in the Gemfile.

$ bundle config gemfile Gemfile-rails4

$ bundle install
# This will install gems from Gemfile-rails4 file.

ssl_ca_cert (BUNDLE_SSL_CA_CERT)

This specifies path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format. You can specify your own https sources in Gemfile with corresponding certificates specified via bundle config.

$ bundle config ssl_ca_cert NEW_CERTIFICATE_PATH

ssl_client_cert (BUNDLE_SSL_CLIENT_CERT)

This specifies path to a designated file containing a X.509 client certificate and key in PEM format.

$ bundle config ssl_client_cert NEW_CERTIFICATE_PATH

cache_path (BUNDLE_CACHE_PATH)

You can set the path to place cached gems while running bundle package.

$ bundle config cache_path vendor/new-cache-path

$ bundle package
Using colorize 0.7.7
Using pg 0.17.1
Using bundler 1.11.2
Updating files in vendor/new-cache-path
  * colorize-0.7.7.gem
  * pg-0.17.1.gem
Bundle complete! 2 Gemfile dependencies, 3 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
Updating files in vendor/new-cache-path

disable_multisource (BUNDLE_DISABLE_MULTISOURCE)

When set, Gemfiles containing multiple sources will produce an error instead of a warning.

With Gemfile,

source 'https://rubygems.org'
source 'http://gems.github.com'

ruby '2.2.2'

When you try to run bundle install, you will get warning.

$ bundle install
Warning: this Gemfile contains multiple primary sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source. To upgrade this warning to an error, run `bundle config disable_multisource true`.
$ bundle config --local disable_multisource true

$ bundle install
[!] There was an error parsing `Gemfile`: Warning: this Gemfile contains multiple primary sources. Each source after the first must include a block to indicate which gems should come from that source. To downgrade this error to a warning, run `bundle config --delete disable_multisource`. Bundler cannot continue.

 #  from /Users/username/Documents/Workspace//Gemfile:2
 #  -------------------------------------------
 #  source 'https://rubygems.org'
 >  source 'http://gems.github.com'
 #
 #  -------------------------------------------

To ignore all bundle config on the machine and run bundle install, set BUNDLE_IGNORE_CONFIG environment variable.

Using D3 JS with React JS

In this blog, we will see how to plot a simple line chart using ReactJS and D3JS.

If you are not familiar with ReactJS then please take a look at official ReactJS webpage. You can also look at our Learn ReactJS in steps video series.

What is D3.js

D3.js is a Javascript library used to create interactive, dynamic visualizations.

Let’s take a step by step look at how we can integrate ReactJS with D3JS to plot some interactive visualizations.

Step 1 - Get ReactJS example working

We will be using JSFiddle example from ReactJS Docs to begin with. Fork the JSFiddle example and you should be good to go.

Step 2 - Add D3.js as an external resource

We will be using D3.js from Cloudflare CDN. Add D3.js as an external resource as shown in the image given below and type the following URL as an external resource.

https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.12/d3.js

Add D3 js as an external resource

Step 3 - Build ReactJS components to create visualizations with D3.js

Now let’s try to draw a Line Chart using D3.js.

Let’s create a Line component that renders line path for the data points provided.

const Line = React.createClass({

  propTypes: {
    path:         React.PropTypes.string.isRequired,
    stroke:       React.PropTypes.string,
    fill:         React.PropTypes.string,
    strokeWidth:  React.PropTypes.number
  },

  getDefaultProps() {
    return {
      stroke:       'blue',
      fill:         'none',
      strokeWidth:  3
    };
  },

  render() {
    let { path, stroke, fill, strokeWidth } = this.props;
    return (
      <path
        d={path}
        fill={fill}
        stroke={stroke}
        strokeWidth={strokeWidth}
        />
    );
  }

});

Here in above code, Line component renders an SVG path. Path data d is generated using D3 path functions.

Let’s create another component DataSeries that will render Line component for each series of data provided. This generates path based on xScale and yScale generated for plotting a line chart.

const DataSeries = React.createClass({

  propTypes: {
    colors:             React.PropTypes.func,
    data:               React.PropTypes.object,
    interpolationType:  React.PropTypes.string,
    xScale:             React.PropTypes.func,
    yScale:             React.PropTypes.func
  },

  getDefaultProps() {
    return {
      data:               [],
      interpolationType:  'cardinal',
      colors:             d3.scale.category10()
    };
  },

  render() {
    let { data, colors, xScale, yScale, interpolationType } = this.props;

    let line = d3.svg.line()
      .interpolate(interpolationType)
      .x((d) => { return xScale(d.x); })
      .y((d) => { return yScale(d.y); });

    let lines = data.points.map((series, id) => {
      return (
        <Line
          path={line(series)}
          stroke={colors(id)}
          key={id}
          />
      );
    });

    return (
      <g>
        <g>{lines}</g>
      </g>
    );
  }

});

Here in above code d3.svg.line creates a new line generator which expects input as a two-element array of numbers.

Now we will create LineChart component that will calculate xScale, yScale based on data and will render DataSeries by passing xScale, yScale, data (input x,y values), width, height for the chart.

const LineChart = React.createClass({

  propTypes: {
    width:  React.PropTypes.number,
    height: React.PropTypes.number,
    data:   React.PropTypes.object.isRequired
  },

  getDefaultProps(){
    return {
      width:  600,
      height: 300
    }
  },

  render() {
    let { width, height, data } = this.props;

    let xScale = d3.scale.ordinal()
                   .domain(data.xValues)
                   .rangePoints([0, width]);

    let yScale = d3.scale.linear()
                   .range([height, 10])
                   .domain([data.yMin, data.yMax]);

    return (
      <svg width={width} height={height}>
          <DataSeries
            xScale={xScale}
            yScale={yScale}
            data={data}
            width={width}
            height={height}
            />
      </svg>
    );
  }

});

Here d3.scale.ordinal constructs an ordinal scale that can have discrete domain while d3.scale.linear constructs a linear quantitative scale.

You can learn more about D3 Quantitative scales here.

Now we need to call LineDataSeries component with the data.

let data = {
  points: [
    [ { x: 0, y: 20 }, { x: 1, y: 30 }, { x: 2, y: 10 }, { x: 3, y: 5 },
      { x: 4, y: 8 }, { x: 5, y: 15 }, { x: 6, y: 10 } ]
    ,
    [ { x: 0, y: 8 }, { x: 1, y: 5 }, { x: 2, y: 20 }, { x: 3, y: 12 },
      { x: 4, y: 4 }, { x: 5, y: 6 }, { x: 6, y: 2 } ]
    ,
    [ { x: 0, y: 0 }, { x: 1, y: 5 }, { x: 2, y: 8 }, { x: 3, y: 2 },
      { x: 4, y: 6 }, { x: 5, y: 4 }, { x: 6, y: 2 } ]
    ],
  xValues: [0,1,2,3,4,5,6],
  yMin: 0,
  yMax: 30
};

ReactDOM.render(
  <LineChart
    data={data}
    width={600}
    height={300}
    />,
  document.getElementById('container')
);

An element with id container is replaced with content rendered by LineChart.

If we take a look at the output now, we see how the Line Chart gets plotted.

ReactJS + D3.js Line Chart example

To build complex visualizations in a modularized fashion, we can use one of the open source libraries mentioned below based on their advantages and disadvantages.

ReactJS + D3.js Open Source Projects

Here are two popular open source ReactJS + D3.JS projects.

react-d3

Pros

  • Supports Bar chart, Line chart, Area chart, Pie chart, Candlestick chart, Scattered chart and Treemap.
  • Legend support.
  • Tooltips support.

Cons

  • No support for Animations. You can implement animations using D3 Transitions.
  • Only stacked Bar chart support.
react-d3-components

Pros

  • Custom scales support.
  • Supports Bar chart (Stacked, Grouped), Line chart, Area chart, Pie chart, Scattered chart.
  • Tooltips support.

Cons

  • No Legend support.
  • No support for Animations.

Summary

Below is final working example of JSFiddle built in the post.

Caching result sets and collection in Rails 5

This blog is part of our Rails 5 series.

Often while developing a Rails application you may look to have one of these caching techniques to boost the performance. Along with these, Rails 5 now provides a way of caching a collection of records, thanks to the introduction of the following method:

ActiveRecord::Relation#cache_key

What is collection caching?

Consider the following example where we are fetching a collection of all users belonging to city of Miami.

@users = User.where(city: 'miami')

Here @users is a collection of records and is an object of class ActiveRecord::Relation.

Whether the result of the above query would be same depends on following conditions.

  • The query statement doesn’t change. If we change city name from “Miami” to “Boston” then result might change.
  • No record is deleted. The count of records in the collection should be same.
  • No record is added. The count of records in the collection should be same.

Rails community implemented caching for a collection of records . Method cache_key was added to ActiveRecord::Relation which takes into account many factors including query statement, updated_at column value and the count of the records in collection.

Understanding ActiveRecord::Relation#cache_key

We have object @users of class ActiveRecord::Relation. Now let’s execute cache_key method on it.

 @users.cache_key
 => "users/query-67ed32b36805c4b1ec1948b4eef8d58f-3-20160116111659084027"

Let’s try to understand each piece of the output.

users represents what kind of records we are holding. In this example we have collection of records of class User. Hence users is to illustrate that we are holding users records.

query- is hardcoded value and it will be same in all cases.

67ed32b36805c4b1ec1948b4eef8d58f is a digest of the query statement that will be executed. In our example it is MD5( "SELECT "users".* FROM "users" WHERE "users"."city" = 'Miami'")

3 is the size of collection.

20160116111659084027 is timestamp of the most recently updated record in the collection. By default, the timestamp column considered is updated_at and hence the value will be the most recent updated_at value in the collection.

Using ActiveRecord::Relation#cache_key

Let’s see how to use cache_key to actually cache data.

In our Rails application, if we want to cache records of users belonging to “Miami” then we can take following approach.

# app/controllers/users_controller.rb

class UsersController < ApplicationController

  def index
    @users = User.where(city: 'Miami')
  end
end

# users/index.html.erb

<% cache(@users) do %>
  <% @users.each do |user| %>
    <p> <%= user.city %> </p>
  <% end %>
<% end %>

# 1st Hit
Processing by UsersController#index as HTML
  Rendering users/index.html.erb within layouts/application
   (0.2ms)  SELECT COUNT(*) AS "size", MAX("users"."updated_at") AS timestamp FROM "users" WHERE "users"."city" = ?  [["city", "Miami"]]
Read fragment views/users/query-37a3d8c65b3f0f9ece7f66edcdcb10ab-4-20160704131424063322/30033e62b28c83f26351dc4ccd6c8451 (0.0ms)
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."city" = ?  [["city", "Miami"]]
Write fragment views/users/query-37a3d8c65b3f0f9ece7f66edcdcb10ab-4-20160704131424063322/30033e62b28c83f26351dc4ccd6c8451 (0.0ms)
Rendered users/index.html.erb within layouts/application (3.7ms)

# 2nd Hit
Processing by UsersController#index as HTML
  Rendering users/index.html.erb within layouts/application
   (0.2ms)  SELECT COUNT(*) AS "size", MAX("users"."updated_at") AS timestamp FROM "users" WHERE "users"."city" = ?  [["city", "Miami"]]
Read fragment views/users/query-37a3d8c65b3f0f9ece7f66edcdcb10ab-4-20160704131424063322/30033e62b28c83f26351dc4ccd6c8451 (0.0ms)
  Rendered users/index.html.erb within layouts/application (3.0ms)

From above, we can see that for the first hit, a count query is fired to get the the latest updated_at and size from the users collection.

Rails will write a new cache entry with a cache_key generated from above count query.

Now on second hit, it again fires count query and checks if cache_key for this query exists or not.

If cache_key is found, it loads data without firing SQL query.

What if your table doesn’t have updated_at column?

Previously we mentioned that cache_key method uses updated_at column. cache_key also provides an option of passing custom column as a parameter and then the highest value of that column among the records in the collection will be considered.

For example if your business logic considers a column named last_bought_at in products table as a factor to decide caching, then you can use the following code.

 products = Product.where(category: 'cars')
 products.cache_key(:last_bought_at)
 => "products/query-211ae6b96ec456b8d7a24ad5fa2f8ad4-4-20160118080134697603"

Edge cases to watch out for

Before you start using cache_key there are some edge cases to watch out for.

Consider you have an application where there are 5 entries in users table with city Miami.

Using limit puts incorrect size in cache key if collection is not loaded.

If you want to fetch three users belonging to city “Miami” then you would execute following query.

 users = User.where(city: 'Miami').limit(3)
 users.cache_key
 => "users/query-67ed32b36805c4b1ec1948b4eef8d58f-3-20160116144936949365"

Here users contains only three records and hence the cache_key has 3 for size of collection.

Now let’s try to execute same query without fetching the records first.

 User.where(name: 'Sam').limit(3).cache_key
 => "users/query-8dc512b1408302d7a51cf1177e478463-5-20160116144936949365"

You can see that the count in the cache is 5 this time even though we have set a limit to 3. This is because the implementation of ActiveRecord::Base#collection_cache_key executes query without limit to fetch the size of the collection.

Cache key doesn’t change when an existing record from a collection is replaced

I want 3 users in the descending order of ids.

 users1 = User.where(city: 'Miami').order('id desc').limit(3)
 users1.cache_key
 => "users/query-57ee9977bb0b04c84711702600aaa24b-3-20160116144936949365"

Above statement will give us users with ids [5, 4, 3].

Now let’s remove the user with id = 3.

 User.find(3).destroy

 users2 = User.where(first_name: 'Sam').order('id desc').limit(3)
 users2.cache_key
 => "users/query-57ee9977bb0b04c84711702600aaa24b-3-20160116144936949365"

Note that cache_key both users1 and users2 is exactly same. This is because none of the parameters that affect the cache key is changed i.e., neither the number of records, nor the query statement, nor the timestamp of the latest record.

There is a discussion undergoing about adding ids of the collection records as part of the cache key. This might help solve the problems discussed above.

Using group query gives incorrect size in the cache key

Just like limit case discussed above cache_key behaves differently when data is loaded and when data is not loaded in memory.

Let’s say that we have two users with first_name “Sam”.

First let’s see a case where collection is not loaded in memory.

 User.select(:first_name).group(:first_name).cache_key
 => "users/query-92270644d1ec90f5962523ed8dd7a795-1-20160118080134697603"

In the above case, the size is 1 in cache_key. For the system mentioned above, the sizes that you will get shall either be 1 or 5. That is, it is size of an arbitrary group.

Now let’s see when collection is first loaded.

 users = User.select(:first_name).group(:first_name)
 users.cache_key
 => "users/query-92270644d1ec90f5962523ed8dd7a795-2-20160118080134697603"

In the above case, the size is 2 in cache_key. You can see that the count in the cache key here is different compared to that where the collection was unloaded even though the query output in both the cases will be exactly same.

In case where the collection is loaded, the size that you get is equal to the total number of groups. So irrespective of what the records in each group are, we may have possibility of having the same cache key value.

Caching in development environment in Rails 5

This blog is part of our Rails 5 series.

In Rails 4 if I’m doing work related to caching then first I need to turn caching “on” by opening file config/environments/development.rb and changing following line.

config.action_controller.perform_caching = false

After changing the value from false to true, I need to restart the server.

This means that if I am testing caching behavior locally then every time I turn caching “on” or “off” I need to restart the server.

New command to create development cache in Rails 5

Rails 5 has introduced a new command to create development cache and help us test how caching behaves in development mode. Here is the issue and here is the pull request.

$ rails dev:cache
Development mode is now being cached.

Execution of the above command creates file caching-dev.txt in tmp directory.

How does it work?

In Rails 5 when a brand new Rails app is created then config/environments/development.rb file will have the following snippet of code.

if Rails.root.join('tmp/caching-dev.txt').exist?
  config.action_controller.perform_caching = true
  config.static_cache_control = "public, max-age=172800"
  config.cache_store = :mem_cache_store
else
  config.action_controller.perform_caching = false
  config.cache_store = :null_store
end

In the above code we are checking if the file tmp/caching-dev.txt is present and then use :mem_cache_store to enable caching only if the file is found.

Also, here is a snippet from the dev cache source code.

def dev_cache
  if File.exist? 'tmp/caching-dev.txt'
    File.delete 'tmp/caching-dev.txt'
    puts 'Development mode is no longer being cached.'
  else
    FileUtils.touch 'tmp/caching-dev.txt'
    puts 'Development mode is now being cached.'
  end

  FileUtils.touch 'tmp/restart.txt'
end

What is the advantage

The advantage is that we do not need to restart the server manually if we want to turn caching “on” or “off”. It is internally taken care by the dev_cache method that is executed when rails dev:cache is executed. You can see in the source code that tmp/restart.txt is being touched.

Please note that this feature is not supported by unicorn, thin and webrick. My guess is that DHH wants this feature because his team uses pow and pow restarts when tmp/restart.txt is touched. He also created an issue for spring to watch tmp/restart.txt long time back.

Disabling development cache

Execute the same command that was used to enable caching. If caching was previously enabled then it will be turned “off” now.

$ rails dev:cache
Development mode is no longer being cached.

Configure PostgreSQL to allow remote connection

By default PostgreSQL is configured to be bound to “localhost”.

$ netstat -nlt
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3737          0.0.0.0:*               LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN

As we can see above port 5432 is bound to 127.0.0.1. It means any attempt to connect to the postgresql server from outside the machine will be refused. We can try hitting the port 5432 by using telnet.

$ telnet 107.170.11.79 5432
Trying 107.170.11.79...
telnet: connect to address 107.170.11.79: Connection refused
telnet: Unable to connect to remote host

Configuring postgresql.conf

In order to fix this issue we need to find postgresql.conf. In different systems it is located at different place. I usually search for it.

$ find \ -name "postgresql.conf"
/var/lib/pgsql/9.4/data/postgresql.conf

Open postgresql.conf file and replace line

listen_addresses = 'localhost'

with

listen_addresses = '*'

Now restart postgresql server.

$ netstat -nlt
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:2812          0.0.0.0:*               LISTEN
tcp6       0      0 ::1:11211               :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 :::5432                 :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN

Here we can see that “Local Address” for port 5432 has changed to 0.0.0.0.

Configuring pg_hba.conf

Let’s try to connect to remote postgresql server using “psql”.

$ psql -h 107.170.158.89 -U postgres
psql: could not connect to server: Connection refused
	Is the server running on host "107.170.158.89" and accepting
	TCP/IP connections on port 5432?

In order to fix it, open pg_hba.conf and add following entry at the very end.

host    all             all              0.0.0.0/0                       md5
host    all             all              ::/0                            md5

The second entry is for IPv6 network.

Do not get confused by “md5” option mentioned above. All it means is that a password needs to be provided. If you want client to allow collection without providing any password then change “md5” to “trust” and that will allow connection unconditionally.

Restart postgresql server.

$ psql -h 107.170.158.89 -U postgres
Password for user postgres:
psql (9.4.1, server 9.4.5)
Type "help" for help.

postgres=# \l

You should be able to see list of databases.

Now we are able to connect to postgresql server remotely.

Please note that in the real world you should be using extra layer of security by using “iptables”.

Rails 5 brings consistency by wrapping all rake commands using rails

This blog is part of our Rails 5 series.

In Rails 4 some commands start with rails and some commands start with rake. This could be quite confusing for people new to Rails. Let’s see an example.

Our task is to write a database migration and then to run that migration.

rails g migration create_users

Above command creates a migration. Now we need to run that migration.

rake db:migrate

As you can see first command starts with rails and second command starts with rake.

In order to consolidate them we can either use rails for everything or we can use rake for everything.

Choosing rails command over rake command

Some favor using rake over rails. But an important feature missing in Rake is the ability to pass arguments.

rails console development

In order to execute the above command using rake we will have to pass console and development as arguments. We can pass these values using environment variables. That would mean adding additional code in Rake task to fetch right values and then only we will be able to invoke command rails console development.

Rails 5 enables executing rake commands with rails

Rails core team decided to have consistency by enabling rails command to support everything that rake does.

For example in Rails 5 commands like db:migrate, setup, test etc which are part of rake command in Rails 4 are now being supported by rails command. However you can still choose to use rake to run those commands similar to how they were run in Rails 4. This is because Rails community has introduced Rake Proxy instead of completely moving the command options from rake to rails.

What happens internally is that when rails db:migrate command is executed, Rails checks if db:migrate is something that rails natively supports or not. In this case db:migrate is not natively supported by rails, so Rails delegates the execution to Rake via Rake Proxy.

If you want to see all the commands that is supported by rails in Rails 5 then you can get a long list of options by executing rails --help.

Use app namespace for framework tasks in Rails 5

As rails command is now preferred over rake command, few rails namespaced framework tasks started looking little odd.

$ rails rails:update

$ rails rails:template

$ rails rails:templates:copy

$ rails rails:update:configs

$ rails rails:update:bin

So, Rails team decided to change the namespace for these tasks from rails to app.

$ rails app:update

$ rails app:template

$ rails app:templates:copy

$ rails app:update:configs

$ rails app:update:bin

Using rails rails:update will now give deprecation warning like: DEPRECATION WARNING: Running update with the rails: namespace is deprecated in favor of app: namespace. Run bin/rails app:update instead.

More improvements in pipeline

In Rails 4, the routes are usually searched like this.

$ rake routes | grep pattern

There is an effort underway to have a Rails command which might work as shown below.

$ rails routes -g pattern

There is also an effort to enable lookup for controller like this.

$ rails routes -c some_controller

Each form gets its own CSRF token in Rails 5

This blog is part of our Rails 5 series.

We have written an extensive blog on what CSRF is and what steps Rails 4 takes to prevent CSRF. We encourage you to read that blog to fully understand rest of this article.

Nested form can get around CSRF protection offered by Rails 4

A typical form generated in Rails 4 might look like this.

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="token_value">
</form>

Using code-injection, a Hacker can add another form tag above the form tag generated by Rails using JavaScript. Now the markup looks like this.

<form method="post" action="http://www.fraud.com/fraud">
  <form method= "post" action="/money_transfer">
    <input type="hidden" name="authenticity_token" value="token_value">
  </form>
</form>

HTML specification does not allow nested forms.

Since nested forms are not allowed browser will accept the top most level form. In this case that happens to be the form created by the hacker. When this form is submitted then “authenticity_token” is also submitted and Rails will do its check and will say everything is looking good and thus hacker will be able to hack the site.

Rails 5 fixes the issue by generating a custom token for a form

In Rails 5, CSRF token can be added for each form. Each CSRF token will be valid only for the method/action of the form it was included in.

You can add following line to your controller to add authenticity token specific to method and action in each form tag of the controller.

class UsersController < ApplicationController
  self.per_form_csrf_tokens = true
end

Adding that code to each controller feels burdensome. In that case you can enable this behavior for all controllers in the application by adding following line to an initializer.

# config/application.rb
Rails.configuration.action_controller.per_form_csrf_tokens = true

This will add authenticity token specific to method and action in each form tag of the application. After adding that token the generated form might look like as shown below.

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="money_transfer_post_action_token">
</form>

Authenticity token included here will be specific to action money_transfer and method post. Attacker can still grab authenticity_token here, but attack will be limited to money_transfer post action.

Rendering views outside of controllers in Rails 5

This blog is part of our Rails 5 series.

Rails request-response cycle is very easy to understand. A request hits the app, a route is matched to a controller action from routes.rb, and finally controller action processes the request and renders HTML or JSON based on the type of the request.

But sometimes we want to render our HTML or JSON response outside of this request-response cycle.

For example let’s say user is allowed to download PDF version of a report on web. This can be done using request-response cycle. We also need to send a weekly report to managers and the email should have the report as an attachment. Now we need to generate the same PDF but since emails are sent using background job the request-response cycle is missing.

Rails 5 has this feature baked in.

Let’s say we have a OrdersController and we want to render individual order outside of controller.

Fire up rails console and execute following command.

OrdersController.render :show, assigns: { order: Order.last }

This will render app/views/orders/show.html.erb with @order set to Order.last. Instance variables can be set using assigns in the same way we use them in controller actions. Those instance variables will be passed to the view that is going to be rendered.

Rendering partials is also possible.

OrdersController.render :_form, locals: { order: Order.last }

This will render app/views/orders/_form.html.erb and will pass order as local variable.

Say I want to render all orders, but in JSON format.

OrdersController.render json: Order.all
# => "[{"id":1, "name":"The Well-Grounded Rubyist", "author":"David A. Black"},
       {"id":2, "name":"Remote: Office not required", "author":"David & Jason"}]

Even rendering simple text is possible.

>> BooksController.render plain: 'this is awesome!'
  Rendered text template (0.0ms)
# => "this is awesome!"

Similar to text, we can also use render file and render template.

Request environment

A typical web request carries it’s own environment with it. We usually handle this environment using request.env in controllers. Certain gems like devise depends on env hash for information such as warden token.

So when we are rendering outside of controller, we need to make sure that the rendering happens with correct environment.

Rails provides a default rack environment for this purpose. The default options used can be accessed through renderer.defaults.

>> OrdersController.renderer.defaults
=> {:http_host=>"example.org", :https=>false, :method=>"get", :script_name=>"", :input=>""}

Internally, Rails will build a new Rack environment based on these options.

Customizing the environment

We can customize environment using method renderer. Let’s say that we need “method as post” and we want “https to be true” for our background job processing.

renderer = ApplicationController.renderer.new(method: 'post', https: true)
# => #<ActionController::Renderer:0x007fdf34453f10 @controller=ApplicationController, @defaults={:http_host=>"example.org", :https=>false, :method=>"get", :script_name=>"", :input=>""}, @env={"HTTP_HOST"=>"example.org", "HTTPS"=>"on", "REQUEST_METHOD"=>"POST", "SCRIPT_NAME"=>"", "rack.input"=>""}>

Now that we have our custom renderer we can use it to generate view.

renderer.render template: 'show', locals: { order: Order.last }

Overall this is a nice feature which enables reuse of existing code.

Not using https might be breaking file uploads

Recently we came across following error when mobile app was trying to upload images using backend API.

==> nginx-error.log <==

2015/12/16 07:34:13 [error] 1440#0: *1021901
sendfile() failed (32: Broken pipe) while sending request to upstream,
client: xxx.xx.xxx.xx, server: app-name.local,
request: "POST /api_endpoint HTTP/1.1",
upstream: "http://unix:/data/apps/app-name/shared/tmp/sockets/unicorn.sock:/api_endpoint",
host: "appname.com"

==> nginx-error.log <==

xxx.xx.xxx.xx - - [16/Dec/2015:07:34:13 - 0500]
"POST /api_endpoint HTTP/1.1" 502 1051 "-"
"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13B143 (366691552)"

The backend API was developed using Ruby on Rails and was powered using NGINX HTTP server along with unicorn application server.

Notice the the http response received was 502 which is documented in RFC as shown below.

10.5.3 502 Bad Gateway The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request.

Debugging the problem

From the first look it seemed that the client_max_body_size parameter for nginx was too less, which might cause the request to fail if the uploaded filesize is greater than the allowed limit.

nginx.conf
http {
  ...
  client_max_body_size 250M;
  ...
}

But that was not the case with our NGINX configuration. The NGINX was configured to accept file size upto 250 megabytes, while the file being uploaded was around 6 megabytes.

In our Rails code we are forcing all traffic to use HTTPS by having production.rb to have following setting.

config.force_ssl = true

What this setting does is, it forces HTTPS by redirecting HTTP requests to their HTTPS counterparts. So any request accessing http://domain.com/path will be redirected to https://domain.com/path

Forcing all traffic to HTTPS still does not explain the vague error sendfile() failed (32: Broken pipe) while sending request to upstream and why the HTTP 502 error which means Bad Gateway

Here is how our nginx.conf is configured.

server {
  ...
  listen 80;
  listen 443 ssl;
  ...
}

NGINX is configured to accept both HTTP and HTTPS requests. This is a pretty standard setting so that application can support both HTTP and HTTPS. What it means is that nginx will accept both HTTP and HTTPS request. It would not force HTTP request to be HTTPS. It would forward HTTP request to rails backend api.

Here is what happens when you upload a file

When we upload a file then NGINX takes that request and passes that request to Rails. NGINX expects a response from Rails only when NGINX is done sending the whole request.

Let’s see what happens when a user visits login page using HTTP. NGINX takes the request and passes the request to Rails. When NGINX is done handing over the request to Rails then NGINX expects a response from Rails. However in this case rather than sending 200 Rails sends a redirect over HTTPS. So now NGINX takes up the request again over HTTPS and then hands over request to Rails. Rails processes the request and returns 200. Everything works out.

Now let’s see what happens when a file is uploaded over HTTP.

User uploads a file over HTTP. NGINX takes up the request and starts sending the file to Rails. More details about the file upload process can be see at RFC. The data is sent to server in chunks. When first chunk is sent to server then server notices that data is being sent over HTTP and it immediately sends a response that data should be sent over HTTPS.

In the meantime on the client side , client is still pushing rest of the data to the server. Client expects a response from the server only when it is done pushing all the data. However in this case server sends a response when client is not expecting it.

NGINX at this time is all confused and thinks something has gone wrong with the gateway and returns HTTP/1.1 502 Bad Gateway and aborts the upload operation. And that how we get the 502 error.

So next time you see an error like this make sure that you are using https to upload the file if server is enforcing https.

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, maxage=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 maxage 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.