Rails 5.2 adds bootsnap to the app to speed up boot time

This blog is part of our Rails 5.2 series.

Rails 5.2 beta 1 was recently released.

If we generate a new Rails app using Rails 5.2, we will see bootsnap gem in the Gemfile. bootsnap helps in reducing the boot time of the app by caching expensive computations.

In a new Rails 5.2 app, boot.rb will contain following content:

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)

require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

if %w[s server c console].any? { |a| ARGV.include?(a) }
  puts "=> Booting Rails"
end

This sets up bootsnap to start in all environments. We can toggle it per environment as required.

This works out of the box and we don’t have do to anything for the new app.

If we are upgrading an older app which already has bootsnap, then we need to make sure that we are using bootsnap >= 1.1.0 because new Rails apps ship with that version constraint.

If the app doesn’t contain the bootsnap gem already then we will need to add it manually since rails app:update task adds the bootsnap/setup line to boot.rb regardless of its presence in the Gemfile.

Ruby 2.5 requires pp by default

This blog is part of our Ruby 2.5 series.

Ruby 2.5.0-preview1 was recently released.

Ruby allows pretty printing of objects using pp method.

Before Ruby 2.5, we had to require PP explicitly before using it. Even the official documentation states that “All examples assume you have loaded the PP class with require ‘pp’”.

>> months = %w(January February March)
=> ["January", "February", "March"]

>> pp months
NoMethodError: undefined method `pp' for main:Object
Did you mean?  p
	from (irb):5
	from /Users/prathamesh/.rbenv/versions/2.4.1/bin/irb:11:

>> require 'pp'
=> true

>> pp months
["January",
 "February",
 "March"]
=> ["January", "February", "March"]

In Ruby 2.5, we don’t need to require pp. It gets required by default. We can use it directly.

>> months = %w(January February March)
=> ["January", "February", "March"]

>> pp months
["January",
 "February",
 "March"]
=> ["January", "February", "March"]

This feature was added after Ruby 2.5.0 preview 1 was released, so it’s not present in the preview. It’s present in Ruby trunk.

Array#prepend and Array#append in Ruby 2.5

This blog is part of our Ruby 2.5 series.

Ruby has Array#unshift to prepend an element to the start of an array and Array#push to append an element to the end of an array.

The names of these methods are not very intuitive. Active Support from Rails already has aliases for the unshift and push methods , namely prepend and append.

In Ruby 2.5, these methods are added in the Ruby language itself.

>> a = ["hello"]
=> ["hello"]
>> a.append "world"
=> ["hello", "world"]
>> a.prepend "Hey"
=> ["Hey", "hello", "world"]
>>

They are implemented as aliases to the original unshift and push methods so there is no change in the behavior.

Ruby 2.5 added yield_self

This blog is part of our Ruby 2.5 series.

Ruby 2.5 added a new method named yield_self. It yields the receiver to the given block and returns output of the last statement in the block.

irb> "Hello".yield_self { |str| str + " World" }
  => "Hello World"

How is it different from try in Rails ?

Without a method argument try behaves similar to yield_self. It would yield to the given block unless the receiver is nil and returns the output of the last statement in the block.

irb> "Hello".try { |str| str + " World" }
  => "Hello World"

Couple of differences to note are, try is not part of Ruby but Rails. Also try’s main purpose is protection against nil hence it doesn’t execute the block if receiver is nil.

irb> nil.yield_self { |obj| "Hello World" }
  => "Hello World"

irb> nil.try { |obj| "Hello World" }
  => nil

What about tap?

tap also is similar to yield_self. It’s part of Ruby itself. The only difference is the value that is returned. tap returns the receiver itself while yield_self returns the output of the block.

irb> "Hello".yield_self { |str| str + " World" }
  => "Hello World"

irb> "Hello".tap { |str| str + " World" }
  => "Hello"

Overall, yield_self improves readability of the code by promoting chaining over nested function calls. Here is an example of both the styles.

irb> add_greeting = -> (str) { "HELLO " + str }
irb> to_upper = -> (str) { str.upcase }

# with new `yield_self`
irb> "world".yield_self(&to_upper)
            .yield_self(&add_greeting)
  => "HELLO WORLD"

# nested function calls
irb> add_greeting.call(to_upper.call("world"))
  => "HELLO WORLD"

yield_self is part of Kernel and hence it’s available to all the objects.

Rails 5.2 implements fetch_values for HashWithIndifferentAccess

This blog is part of our Rails 5.2 series.

Ruby 2.3 added fetch_values method to hash.

By using fetch_values we are able to get values for multiple keys in a hash.

capitals = { usa: "Washington DC",
             china: "Beijing",
             india: "New Delhi",
             australia: "Canberra" }

capitals.fetch_values(:usa, :india)
#=> ["Washington DC", "New Delhi"]

capitals.fetch_values(:usa, :spain) { |country| "N/A" }
#=> ["Washington DC", "N/A"]

Rails 5.2 introduces method fetch_values on HashWithIndifferentAccess. We’ll hence be able to fetch values of multiple keys on any instance of HashWithIndifferentAccess class.

capitals = HashWithIndifferentAccess.new
capitals[:usa] = "Washington DC"
capitals[:china] = "Beijing"

capitals.fetch_values("usa", "china")
#=> ["Washington DC", "Beijing"]

capitals.fetch_values("usa", "spain") { |country| "N/A" }
#=> ["Washington DC", "N/A"]

Ruby 2.5 added delete_prefix and delete_suffix methods

This blog is part of our Ruby 2.5 series.

Ruby 2.4

Let’s say that we have a string Projects::CategoriesController and we want to remove Controller. We can use chomp method.

irb> "Projects::CategoriesController".chomp("Controller")
  => "Projects::Categories"

However if we want to remove Projects:: from the string then there is no corresponding method of chomp. We need to resort to sub.

irb> "Projects::CategoriesController".sub(/Projects::/, '')
  => "CategoriesController"

Naotoshi Seo did not like using regular expression for such a simple task. He proposed that Ruby should have a method for taking care of such tasks.

Some of the names proposed were remove_prefix, deprefix, lchomp, remove_prefix and head_chomp.

Matz suggested the name delete_prefix and this method was born.

Ruby 2.5.0-preview1

irb> "Projects::CategoriesController".delete_prefix("Projects::")
  => "CategoriesController"

Now in order to delete prefix we can use delete_prefix and to delete suffix we could use chomp. This did not feel right. So for symmetry delete_suffix was added.

irb> "Projects::CategoriesController".delete_suffix("Controller")
  => "Projects::Categories"

Read up on this discussion to learn more about how elixir, go, python, and PHP deal with similar requirements.

Ruby 2.5 introduces Dir.children and Dir.each_child

This blog is part of our Ruby 2.5 series.

Dir.entries is a method present in Ruby 2.4. It returns the output of shell command ls -a in an array.

 > Dir.entries("/Users/john/Desktop/test")
 => [".", "..", ".config", "program.rb", "group.txt"]

We also have method Dir.foreach which iterates and yields each value from the output of ls -a command to the block.

> Dir.foreach("/Users/john/Desktop/test") { |child| puts child }
.
..
.config
program.rb
group.txt
test2

We can see that the output includes the directives for current directory and parent directory which are "." and "..".

When we want to have access only to the children files and directories, we do not need the [".", ".."] subarray.

This is a very common use case and we’ll probably have to do something like Dir.entries(path) - [".", ".."] to achieve the desired output.

To overcome such issues, Ruby 2.5 introduced Dir.children. It returns the output of ls -a command without the directives for current and parent directories.

> Dir.children("/Users/mohitnatoo/Desktop/test")
 => [".config", "program.rb", "group.txt"]

Additionally, we can use Dir.each_child method to avoid yielding current and parent directory directives while iterating,

> Dir.each_child("/Users/mohitnatoo/Desktop/test") { |child| puts child }
.config
program.rb
group.txt
test2

As noted in the discussion the names were chosen to match with existing methods Pathname#children and Pathname#each_child.

These additions seem like simple features. Well the issue was posted more than two years ago.

Higher Order Component for rendering spinner in React Native app

In one of our previous blogs, we mentioned how recompose improves both the readability and the maintainability of the code.

We also saw how branch and renderComponent functions from recompose help us in deciding which component to render based on a condition.

We can use the code from renderComponent documentation to render a spinner component when the data is being fetched in a ReactJS application.

Initial Code

// PatientsList.js

import React, { Component } from 'react';
import LoadingIndicator from './LoadingIndicator';

export default class PatientsList extends Component {

  state = {
    isLoading: true,
    patientsList: [],
  }

  componentDidMount() {
    api.getPatientsList().then(responseData => {
      this.setState({
        patientsList: responseData,
        isLoading: false,
      })
    })
  }

  render() {
    const { isLoading } = this.state;
    if (isLoading) {
      return <LoadingIndicator isLoading={isLoading} />
    } else {
      return (
        <ScrollView>
          // Some header component
          // View rendering the patients
        </ScrollView>
      )
    }
  }

In the above code, when the PatientsList component mounts, it fetches the list of patients from the API. During this time, the isLoading state is true, so we render the LoadingIndicator component.

Once the API call returns with the response, we set the isLoading state to false. This renders ScrollView component, with our list of patients.

The above code works fine, but if our app has multiple screens, which show the loading indicator and fetch data, the above way of handling it becomes repetitive and hard to maintain.

Building a higher order component

Here’s where Higher Order Components(HOC) are very useful. We can extract the logic for the ability to show the loading indicator in a HOC.

// withSpinner.js

import React from 'react';
import { ScrollView } from 'react-native';
import LoadingIndicator from './LoadingIndicator';

const withSpinner = Comp => ({ isLoading, children, ...props }) => {
  if (isLoading) {
    return <LoadingIndicator isLoading={isLoading} />
  } else {
    return (
      <Comp {...props}>
        {children}
      </Comp>
    )
  }
};

export default withSpinner;

Here, we created a HOC component which accepts a component and the isLoading prop.

If isLoading is true, we show the LoadingIndicator. If isLoading is false, we show the supplied component with its children, and pass in the props.

Now, we can use the above HOC in our PatientsList.js file. The supplied component can be any React Native component based on the use case. Here in our case, its a ScrollView.

// PatientsList.js

import { ScrollView } from 'react-native';
import withSpinner from './withSpinner';
const ScrollViewWithSpinner = withSpinner(ScrollView);

export default class PatientsList extends Component {

  state = {
    isLoading: true,
    patientsList: [],
  }

  componentDidMount() {
    api.getPatientsList().then(responseData => {
      this.setState({
        patientsList: responseData,
        isLoading: false,
      })
    })
  }

  render() {
    const { isLoading } = this.state;
    return(
      <ScrollViewWithSpinner
        isLoading={isLoading}
        // other props
      >
        // Some header component
        // View rendering the patients
      </ScrollViewWithSpinner>
    )
  }

Conclusion

Because of the above extraction of logic to a HOC, we can now use the same HOC in all our components which render a loading indicator while the data is being fetched.

The logic to show a loading indicator now resides in a HOC. This makes the code easier to maintain and less repetitive.

Rails 5.1 does not load all records on ActiveRecord::Relation#inspect

This blog is part of our Rails 5.1 series.

Let’s take a project with hundreds of users. When we call inspect on User.all, we see an array of 10 users followed by .... That means the output of #inspect method shows data only for 10 records.

> User.all.inspect
User Load (3.7ms)  SELECT  "users".* FROM "users"
=> "#<ActiveRecord::Relation [
#<User id: 1, email: \"dirbee@example.com\" >,
#<User id: 2, email: \"tee@example.com\">,
#<User id: 3, email: \"scott@example.com\">,
#<User id: 4, email: \"mark@example.com\">,
#<User id: 5, email: \"ben@example.com\">,
#<User id: 6, email: \"tina@example.com\">,
#<User id: 7, email: \"tyler@example.com\">,
#<User id: 8, email: \"peter@example.com\">,
#<User id: 9, email: \"rutul@example.com\">,
#<User id: 10, email:\"michael@example.com\">,
...]>"

We can see that the query executed in the process is fetching all the records even though the output doesn’t need all of them.

In Rails 5.1, only the needed records are loaded when inspect is called on ActiveRecord::Relation.

> User.all.inspect
User Load (3.7ms)  SELECT  "users".* FROM "users" LIMIT $1 /*application:Ace Invoice*/  [["LIMIT", 11]]

=> "#<ActiveRecord::Relation [
#<User id: 1, email: \"dirbee@example.com\" >,
#<User id: 2, email: \"tee@example.com\">,
#<User id: 3, email: \"scott@example.com\">,
#<User id: 4, email: \"mark@example.com\">,
#<User id: 5, email: \"ben@example.com\">,
#<User id: 6, email: \"tina@example.com\">,
#<User id: 7, email: \"tyler@example.com\">,
#<User id: 8, email: \"peter@example.com\">,
#<User id: 9, email: \"rutul@example.com\">,
#<User id: 10, email:\"michael@example.com\">,
...]>"

We can see in the above case that query executed has limit constraint and hence only the required number of records are loaded.

Fixing CORS issue with AWS services

While working on a client project, we started facing an issue where the JWPlayer stopped playing videos when we switched to hls version of videos. We found a CORS error in the JS console as shown below.

cors error

After researching we found that JWPlayer makes an AJAX request to load the m3u8 file. To fix the issue, we needed to enable CORS and for that we needed to make changes to S3 and Cloudfront configurations.

S3 configuration changes

We can configure CORS for the S3 bucket by allowing requests originating from specified hosts. As show in the image below we can find the CORS configuration option in Permissions tab of the S3 bucket. Here is the official documentation on configuring CORS for S3.

s3 cors configuration

S3 bucket will now allow requests originating from the specified hosts.

Cloudfront configuration changes

Cloudfront is a CDN service provided by AWS which uses edge locations to speed up the delivery of static content. Cloudfront takes content from S3 buckets and caches it at edge locations and delivers it to the end user. For enabling CORS we need to configure Cloudfront to allow forwarding of required headers.

We can configure the behavior of Cloudfront by clicking on Cloudfront Distribution’s “Distribution Settings”. Then from the “Behaviour” tab click on “Edit”. Here we need to whitelist the headers that need to be forwarded. Select the “Origin” header to whitelist which is required for CORS, as shown in the image below.

cloudfront behaviour

Ruby 2.5 allows rescue/else/ensure inside do/end blocks

This blog is part of our Ruby 2.5 series.

Ruby 2.4

irb> array_from_user = [4, 2, 0, 1]
  => [4, 2, 0, 1]

irb> array_from_user.each do |number|
irb>   p 10 / number
irb> rescue ZeroDivisionError => exception
irb>   p exception
irb>   next
irb> end
SyntaxError: (irb):4: syntax error, unexpected keyword_rescue,
expecting keyword_end
rescue ZeroDivisionError => exception
      ^

Ruby 2.4 throws error when we try to use rescue/else/ensure inside do/end blocks.

Ruby 2.5.0-preview1

irb> array_from_user = [4, 2, 0, 1]
  => [4, 2, 0, 1]
irb> array_from_user.each do |number|
irb>   p 10 / number
irb> rescue ZeroDivisionError => exception
irb>   p exception
irb>   next
irb> end
2
5
#<ZeroDivisionError: divided by 0>
10
 => [4, 2, 0, 1]

Ruby 2.5 supports rescue/else/ensure inside do/end blocks.

Here is relevant commit and discussion.

Rails now compares large integers using numericality validation accurately

Let’s see an example of numerical validation of very large numbers.

class Score
  validates :total, numericality: { less_than_or_equal_to: 10_000_000_000_000_000 }
end


> score = Score.new(total: (10_000_000_000_000_000 + 1).to_s)
> score.total
#=> 1.0e+16

> score.invalid?
#=> false

Here, we have added numerical validation on total column of Score model that it should be less than 10_000_000_000_000_000.

After that we have created one instance of this model with total greater than allowed value. This should result in an invalid object as it violates the numericality criteria.

But it is still valid. We can also see that value of total has been converted into floating number instead of integer. This happens because Rails used to convert the input to float if it was not already numeric.

The real problem is here is that the floating point comparison of the Ruby language itself which is not accurate for very large numbers.

>> a = (10_000_000_000_000_000 + 1).to_s
=> "10000000000000001"
>> b = Kernel.Float a
=> 1.0e+16
>> c = b + 1
=> 1.0e+16
>> c < b
=> false
>> c > b
=> false
>>

This issue has been fixed in Rails here. Now, if the given string input can be treated as integer, then an integer value is returned instead of float. This makes sure that the comparison works correctly.

# Rails 5.2

> score = Score.new(total: (10_000_000_000_000_000 + 1).to_s)
> score.total
#=> 10000000000000001

> score.invalid?
#=> true

This change is present in Rails 5.2 and above. It also backported to Rails 5.1 and Rails 5.0 branches.

Ruby 2.5 has removed top level constant lookup

This blog is part of our Ruby 2.5 series.

Ruby 2.4

irb> class Project
irb> end
=> nil

irb> class Category
irb> end
=> nil

irb> Project::Category
(irb):5: warning: toplevel constant Category referenced by Project::Category
 => Category

Ruby 2.4 returns top level constant with a warning if it is unable to find find constant in the specified scope.

This does not work well in cases where we need constants to be defined with same name at top level and also in same scope.

Ruby 2.5.0-preview1

irb> class Project
irb> end
=> nil

irb> class Category
irb> end
=> nil

irb> Project::Category
NameError: uninitialized constant Project::Category
Did you mean?  Category
	from (irb):5

Ruby 2.5 throws an error if it is unable to find constant in the specified scope.

Here is relevant commit and discussion.

Scheduling pods on nodes in Kubernetes using labels

This post assumes that you have basic understanding of Kubernetes terms like pods, deployments and nodes.

A Kubernetes cluster can have many nodes. Each node in turn can run multiple pods. By default Kubernetes manages which pod will run on which node and this is something we do not need to worry about it.

However sometimes we want to ensure that certain pods do not run on the same node. For example we have an application called wheel. We have both staging and production version of this app and we want to ensure that production pod and staging pod are not on the same host.

To ensure that certain pods do not run on the same host we can use nodeSelector constraint in PodSpec to schedule pods on nodes.

Kubernetes cluster

We will use kops to provision cluster. We can check the health of cluster using kops validate-cluster.

$ kops validate cluster
Using cluster from kubectl context: test-k8s.nodes-staging.com

Validating cluster test-k8s.nodes-staging.com

INSTANCE GROUPS
NAME              ROLE   MACHINETYPE MIN MAX SUBNETS
master-us-east-1a Master m4.large    1   1 us-east-1a
master-us-east-1b Master m4.large    1   1 us-east-1b
master-us-east-1c Master m4.large    1   1 us-east-1c
nodes-wheel-stg   Node   m4.large    2   5 us-east-1a,us-east-1b
nodes-wheel-prd   Node   m4.large    2   5 us-east-1a,us-east-1b

NODE STATUS
           NAME                ROLE   READY
ip-192-10-110-59.ec2.internal  master True
ip-192-10-120-103.ec2.internal node   True
ip-192-10-42-9.ec2.internal    master True
ip-192-10-73-191.ec2.internal  master True
ip-192-10-82-66.ec2.internal   node   True
ip-192-10-72-68.ec2.internal   node   True
ip-192-10-182-70.ec2.internal  node   True

Your cluster test-k8s.nodes-staging.com is ready

Here we can see that there are two instance groups for nodes: nodes-wheel-stg and nodes-wheel-prd.

nodes-wheel-stg might have application pods like pod-wheel-stg-sidekiq, pod-wheel-stg-unicorn and pod-wheel-stg-redis. Smilarly nodes-wheel-prd might have application pods like pod-wheel-prd-sidekiq, pod-wheel-prd-unicorn and pod-wheel-prd-redis.

As we can see the Max number of nodes for instance group nodes-wheel-stg and nodes-wheel-prd is 5. It means if new nodes are created in future then based on the instance group the newly created nodes will automatically be labelled and no manual work is required.

Labelling a Node

We will use kubernetes labels to label a node. To add a label we need to edit instance group using kops.

$ kops edit ig nodes-wheel-stg

This will open up instance group configuration file, we will add following label in instance group spec.

nodeLabels:
   type: wheel-stg

Complete ig configuration looks like this.

apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: 2017-10-12T06:24:53Z
  labels:
    kops.k8s.io/cluster: k8s.nodes-staging.com
  name: nodes-wheel-stg
spec:
  image: kope.io/k8s-1.7-debian-jessie-amd64-hvm-ebs-2017-07-28
  machineType: m4.large
  maxSize: 5
  minSize: 2
  nodeLabels:
    type: wheel-stg
  role: Node
  subnets:
  - us-east-1a
  - us-east-1b
  - us-east-1c

Similarly, we can label for instance group nodes-wheel-prod with label type wheel-prod.

After making the changes update cluster using kops rolling update cluster --yes --force. This will update the cluster with specified labels.

New nodes added in future will have labels based on respective instance groups.

Once nodes are labeled we can verify using kubectl describe node.

$ kubectl describe node ip-192-10-82-66.ec2.internal
Name:               ip-192-10-82-66.ec2.internal
Roles:              node
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/instance-type=m4.large
                    beta.kubernetes.io/os=linux
                    failure-domain.beta.kubernetes.io/region=us-east-1
                    failure-domain.beta.kubernetes.io/zone=us-east-1a
                    kubernetes.io/hostname=ip-192-10-82-66.ec2.internal
                    kubernetes.io/role=node
                    type=wheel-stg

In this way we have our node labeled using kops.

Labelling nodes using kubectl

We can also label node using kubectl.

$ kubectl label node ip-192-20-44-136.ec2.internal type=wheel-stg

After labeling a node, we will add nodeSelector field to our PodSpec in deployment template.

We will add the following block in deployment manifest.

nodeSelector:
  type: wheel-stg

We can add this configuration in original deployment manifest.

apiVersion: v1
kind: Deployment
metadata:
  name: test-staging-node
  labels:
    app: test-staging
  namespace: test
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: test-staging
    spec:
      containers:
      - image: <your-repo>/<your-image-name>:latest
        name: test-staging
        imagePullPolicy: Always
        - name: REDIS_HOST
          value: test-staging-redis
        - name: APP_ENV
          value: staging
        - name: CLIENT
          value: test
        ports:
        - containerPort: 80
      nodeSelector:
        type: wheel-stg
      imagePullSecrets:
        - name: registrykey

Let’s launch this deployment and check where the pod is scheduled.

$ kubectl apply -f test-deployment.yml
deployment "test-staging-node" created

We can verify that our pod is running on node type=wheel-stg.

kubectl describe pod test-staging-2751555626-9sd4m
Name:           test-staging-2751555626-9sd4m
Namespace:      default
Node:           ip-192-10-82-66.ec2.internal/192.10.82.66
...
...
Conditions:
  Type           Status
  Initialized    True
  Ready          True
  PodScheduled   True
QoS Class:       Burstable
Node-Selectors:  type=wheel-stg
Tolerations:     node.alpha.kubernetes.io/notReady:NoExecute for 300s
                 node.alpha.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>

Similarly we run nodes-wheel-prod pods on nodes labeled with type: wheel-prod.

Please note that when we specify nodeSelector and no node matches label then pods are in pending state as they dont find node with matching label.

In this way we schedule our pods to run on specific nodes for certain use-cases.

SAML integration with multiple IDPs using Devise & OmniAuth

Recently, we integrated our SAML service provider(SP) with multiple identity providers(IDPs) to facilitate Single sign-on(SSO) using Devise with OmniAuth.

Before we jump into the specifics, here is SAML definition from wikipedia.

Security Assertion Markup Language (SAML, pronounced sam-el) is an open standard for exchanging authentication and authorization data between parties, in particular, between an identity provider(IDP) and a service provider(SP).

The choice of Devise with OmniAuth-SAML to build SAML SSO capabilities was natural to us, as we already had dependency on Devise and OmniAuth nicely integrates with Devise.

Here is the official overview on how to integrate OmniAuth with Devise.

After following the overview, this is how our config and user.rb looked like.

# config file
Devise.setup do |config|
  config.omniauth :saml,
    idp_cert_fingerprint: 'fingerprint',
    idp_sso_target_url: 'target_url'
end

#user.rb file
devise :omniauthable, :omniauth_providers => [:saml]

The problem with above configuration is that it supports only one SAML IDP.

To have support for multiple IDPs, we re-defined files as below.

# config file
Devise.setup do |config|
  config.omniauth :saml_idp1,
    idp_cert_fingerprint: 'fingerprint-1',
    idp_sso_target_url: 'target_url-1'
    strategy_class: ::OmniAuth::Strategies::SAML,
    name: :saml_idp1

  config.omniauth :saml_idp2,
    idp_cert_fingerprint: 'fingerprint-2',
    idp_sso_target_url: 'target_url-2'
    strategy_class: ::OmniAuth::Strategies::SAML,
    name: :saml_idp2
end

#user.rb file
devise :omniauthable, :omniauth_providers => [:saml_idp1, :saml_idp2]

Let’s go through the changes one by one.

1. Custom Providers: Instead of using standard provider saml, we configured custom providers (saml_idp1, saml_idp2) in the first line of configuration as well as in user.rb

2. Strategy Class: In case of the standard provider(saml), Devise can figure out strategy_class on its own. For custom providers, we need to explicitly specify it.

3. OmniAuth Unique Identifier: After making the above two changes, everything worked fine except OmniAuth URLs. For some reason, OmniAuth was still listening to saml scoped path instead of new provider names saml_idp1, saml_idp2.

# Actual metadata path used by OmniAuth
/users/auth/saml/metadata

# Expected metadata path
/users/auth/saml_idp1/metadata
/users/auth/saml_idp2/metadata

After digging in Devise and OmniAuth code bases, we discovered provider name configuration. In the absence of this configuration, OmniAuth falls back to strategy class name to build the path. As we could not find any code in Devise which defined name for OmniAuth that explained saml scoped path (we were expecting Devise to pass name assigning same value as provider).

After adding name configuration, OmnitAuth started listening to the correct URLs.

4. Callback Actions: Lastly, we added both actions in OmniauthCallbacksController:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def saml_idp1
    # Implementation
  end

  def saml_idp2
    # Implementation
  end

  # ...
  # Rest of the actions
end

With these changes along with the official guide mentioned above, our SP was able to authenticate users from multiple IDPs.

Rails 5.2 adds expiry option for signed and encrypted cookies and adds relative expiry time

This blog is part of our Rails 5.2 series.

In Rails 5.1 we have option to set expiry for cookies.

cookies[:username] = {value: "sam_smith", expiry: Time.now + 4.hours}

The above code sets cookie which expires in 4 hours.

The expiry option, is not supported for signed and encrypted cookies. In other words we are not able to decide on server side when an encrypted or signed cookie would expire.

From Rails 5.2, we’ll be able to set expiry for encrypted and signed cookies as well.

cookies.encrypted[:firstname] = { value: "Sam", expiry: Time.now + 1.day }
# sets string `Sam` in an encrypted `firstname` cookie for 1 day.

cookies.signed[:lastname] =  {value: "Smith", expiry: Time.now + 1.hour }
# sets string `Smith` in a signed `lastname` cookie for 1 hour.

Apart from this, in Rails 5.1, we needed to provide an absolute date/time value for expires option.

# setting cookie for 90 minutes from current time.
cookies[:username] = {value: "Sam", expiry: Time.now + 90.minutes}

Starting Rails 5.2, we’ll be able to set the expiry option by giving a relative duration as value.

# setting cookie for 90 minutes from current time.
cookies[:username] = { value: "Sam", expiry: 90.minutes }

# After 1 hour
> cookies[:username]
#=> "Sam"

# After 2 hours
> cookies[:username]
#=> nil

Optimize JavaScript code for composability with Ramda.js

In this blog R stands for Ramda.js. More on this later.

Here is code without R.

function isUnique(element, selector) {
  const parent = element.parentNode;
  const elements = parents.querySelectorAll(selector);
  return (elements.length === 1) && (elements[0] === element);
}

Code with R.

function isUnique(element, selector) {
  const querySelectorAll = R.invoker(1, 'querySelectorAll')(selector);

  return R.pipe(
    R.prop('parentNode'),
    querySelectorAll,
    elements => R.both(
                  R.equals(R.length(elements), 1),
                  R.equals(elements[0], element)
                );
  )();
}

Is the refactored code better ?

What is R? What’s invoker? What’s pipe?

The “code without R” reads fine and even a person who has just started learning JavaScript can understand it. Then why take all this extra complexity. Shouldn’t we be writing code that is easier to understand ?

Good questions. Who could be against writing code that is easier to understand.

If all I’m writing is a function called isUnique then of course the “before version” is simpler. However this function is part of a bigger thousands of lines of code software.

A big software is nothing but a collection of smaller pieces of code. We compose code together to make code work.

We need to optimize for composability and as we write code that is more composable, we are finding that composable code is also easier to read.

At BigBinary we have been experimenting with composability. We previously wrote a blog on how using Recompose is making our React components more composable.

Now we are trying same techniques at pure JavaScript level using Ramda.js.

Let’s take a look at another examples.

Example 2

We have a list of users with name and status.

var users = [ { name: "John", status: "Active"},
              { name: "Mike", status: "Inactive"},
              { name: "Rachel", status: "Active" }
             ]

We need to find all active users. Here is a version without R.

jsfiddle

var activeUsers = function(users) {
	return users.filter(function(user) {
  	var status = user.status;
  	return status === 'Active';
  });
};

Here is code with R.

jsfiddle

var isStatusActive = R.propSatisfies(R.equals("Active"), 'status');
var active = R.filter(isStatusActive);
var result = active(users);

Now let’s say that user data changes and we have a user with an empty name. We don’t want to include such users. Now data looks like this.

var users = [ { name: "John", status: "Active"},
              { name: "Mike", status: "Inactive"},
              { name: "Rachel", status: "Active" },
              { name: "",       status: "Active" },
             ]

Here is modified code without R.

jsfiddle

var activeUsers = function(users) {
	return users.filter(function(user) {
  	var status = user.status;
  	var name = user.name;
    return name !== null &&
           name !== undefined &&
           name.length !==0 &&
           status === 'Active'
  });
};

Here is modified code with R.

jsfiddle

var isStatusActive = R.propSatisfies(R.equals("Active"), 'status');
var active = R.filter(isStatusActive);
var isNameEmpty = R.propSatisfies(R.isEmpty, 'name');
var rejectEmptyNames = R.reject(isNameEmpty);
var result = R.pipe(active, rejectEmptyNames)(users);
log(result);

Notice that change we needed to do to accomodate this request.

In the none R version, we had to get into the gut of the function and add logic. In the with R version we added new function and we just composed this new function with old function using pipe. We did not change the existing function.

Now let’s say that we don’t want all the users but just the first two users. We know what need to change in the without R version. In the with R version all we need to do is add R.take(2) and no existing function changes at all.

Here is the final code.

jsfiddle

var isStatusActive = R.propSatisfies(R.equals("Active"), 'status');
var active = R.filter(isStatusActive);
var isNameEmpty = R.propSatisfies(R.isEmpty, 'name');
var rejectEmptyNames = R.reject(isNameEmpty);

var result = R.pipe(active, rejectEmptyNames, R.take(2))(users);
log(result);

Data comes at the end

Another thing to notice is that in the R version nowhere we have said that we are acting on the users. All the functions have no mention of users. Infact all the functions do not take any argument explicitly since the functions are curried. When we want result then we are passing users as the argument but it could be articles and our code will still hold.

This is pointfree programming. We do not need to know about “pointfree” since this comes naturally when write with R.

I’m still not convinced that Ramda.js is solving any real problem

No problem.

Pleas watch Hery Underscore, You’re doing it wrong video by Brian Lonsdorf. Hopefully that will convince you to give Ramda.js a try.

If you are still not convinced then, the author of Ramda.js has written a series of blogs called Thinking in Ramda. Please read the blogs. Slowly.

Ramda brings functional concepts to JavaScript

Functional programming is another way of thinking about the code. When we move to Elm, Haskell or Elixir to get functional concepts then we are wrestling with two things at once - a new language and functional concepts.

Ramda.js brings functional concepts to JavaScript. In this way we can slowly start using functional concepts in our day to day JavaScript code.

The best part is that if you write any JavaScript code then you can start using Ramda.js today. Whether you are using React.js or Angular.js, it’s all JavaScript and you can use Ramda.js.

Elm Conf 2017 Summary

I attended Elm Conf 2017 US last week alongside Strangeloop conference. I was looking forward to the conference to know what the Elm community is working on and what problems people are facing and what are they doing to overcome those.

After attending the conference, I can say that Elm community is growing strong. The conference was attended by around 350 people and many were using Elm in production. More number of people wanted to try Elm in production.

There was a lot of enthusiasm about starting new Elm meetups. As a Ruby on Rails and React meetup organizer myself, I was genuinely interested in hearing experiences of seasoned meetup organizers. In general Evan and Richard prefer meetup to be a place where people form small groups and hack on something rather than one person teaching the whole group something.

I liked all the talks. There was variety in the topics and the speakers were all seasoned. Kudos to the organizers for putting up a great program. Below is a quick summary of my thoughts from the conference.

Keynote by Evan

Evan talked about the work he has been doing for the upcoming release of Elm. He discussed the optimization work related to code splitting, code generation and minification for speeding up building and delivering single page apps using Elm. He made another interesting point that he changed the codegen which generates the JS code from Elm code twice but nobody noticed it. Things like this can give a huge opportunity to change and improve existing designs which he has been doing for the upcoming release.

In the end he mentioned that his philosophy is not to rush things. It’s better to do things right than doing it now.

After the keynote, he encouraged people to talk to him about what they are working on which was really nice.

Accessibility with Elm

Tessa talked about her work around adding accessibility support for Elm apps. She talked about design decisions, prior art and some of the challenges she faced while working on the library like working with tabs, interactive elements and images. There was a question at the end about whether this will be incorporated into Elm core but Evan mentioned that it might take some time.

Putting the Elm Platform in the Browser

Luke, the creator of Ellie - a way to easily share your elm code with others online - talked about how he started with Ellie. He talked about the problems he had to face for implementing and sustaining Ellie through ads. During the talk, he also open sourced the code, so we can see it on Github now.

Luke mentioned how he changed the architecture of Ellie from mostly running on the server to running in the browser using service workers. He discussed future plans about sustaining Ellie, building an Elm editor instead of using Codemirror, getting rid of ads and making Ellie better for everyone.

The Importance of Ports

In other frameworks like PureScript and BuckleScript invoking native JavaScript functions is easy. In Elm one has to use “Ports”. Using Ports requires some extra stuff. In return we get more safety.

Murphy Randle presented a case where he was using too many ports which was resulting in fragmented code. He discussed how port is based on Actor Model and once we get that then using port would be much easier. He also showed refactored code.

Murphy also runs Elm Town Podcast. Listen to episode 13 to know more about Ports.

Keynote by Richard Feldman

Richard talked about his experiences in teaching beginners about Elm. He has taught Elm a lot. He has done an extensive Elm course on Front end masters. He is currently writing Elm in Action book.

He talked about finding motivation to teach using the SWBAT technique. It helped him in deciding the agenda and finding the direct path for teaching. He mentioned that in the beginning being precise and detailed is not important. This resonated with me as the most important thing for anyone who is getting started is getting started with the most basic things and then iterating over it again and again.

Parting thoughts

Elm community is small, tight, very friendly and warm. Lots of people are trying a lot of cool things. Elm Slack came in the discussions again and again as a good place to seek out help for beginners.

When I heard about Elm first, it was about good compiler errors and having run time safety. However after attending the conference I am mighty impressed with the Elm community.

Big props to Brian and Luke for organizing the conference!

All the videos from the conference are already getting uploaded here.

Ruby 2.4 has optimized enumerable min max methods

This blog is part of our Ruby 2.4 series.

Enumerables in Ruby have min, max and minmax comparison methods which are quite convenient to use.

(1..99).min         #=> 1
(1..99).max         #=> 99
(1..99).minmax      #=> [1, 99]

In Ruby 2.4, Enumurable#min, Enumurable#max methods and Enumurable#minmax method are now more optimized.

We would run the following benchmark snippet for both Ruby 2.3 and Ruby 2.4 and observe the results

require 'benchmark/ips'

Benchmark.ips do |bench|
  NUM1 = 1_000_000.times.map { rand }

  ENUM_MIN = Enumerable.instance_method(:min).bind(NUM1)
  ENUM_MAX = Enumerable.instance_method(:max).bind(NUM1)
  ENUM_MINMAX = Enumerable.instance_method(:minmax).bind(NUM1)

  bench.report('Enumerable#min') do
    ENUM_MIN.call
  end

  bench.report('Enumerable#max') do
    ENUM_MAX.call
  end

  bench.report('Enumerable#minmax') do
    ENUM_MINMAX.call
  end
end

Results for Ruby 2.3

Warming up --------------------------------------
      Enumerable#min     1.000  i/100ms
      Enumerable#max     1.000  i/100ms
   Enumerable#minmax     1.000  i/100ms
Calculating -------------------------------------
      Enumerable#min     14.810  (±13.5%) i/s -     73.000  in   5.072666s
      Enumerable#max     16.131  (± 6.2%) i/s -     81.000  in   5.052324s
   Enumerable#minmax     11.758  (± 0.0%) i/s -     59.000  in   5.026007s

Ruby 2.4

Warming up --------------------------------------
      Enumerable#min     1.000  i/100ms
      Enumerable#max     1.000  i/100ms
   Enumerable#minmax     1.000  i/100ms
Calculating -------------------------------------
      Enumerable#min     18.091  (± 5.5%) i/s -     91.000  in   5.042064s
      Enumerable#max     17.539  (± 5.7%) i/s -     88.000  in   5.030514s
   Enumerable#minmax     13.086  (± 7.6%) i/s -     66.000  in   5.052537s

From the above benchmark results, it can be seen that there has been an improvement in the run times for the methods.

Internally Ruby has changed the logic by which objects are compared, which results in these methods being optimized. You can have a look at the commits here and here.

CSV::Row#each etc. return enumerator when no block given

This blog is part of our Ruby 2.4 series.

In Ruby 2.3, These methods do not return enumerator when no block is given.

Ruby 2.3

CSV::Row.new(%w(banana mango), [1,2]).each #=> #<CSV::Row "banana":1 "mango":2>

CSV::Row.new(%w(banana mango), [1,2]).delete_if #=> #<CSV::Row "banana":1 "mango":2>

Some methods raise exception because of this behavior.

> ruby -rcsv -e 'CSV::Table.new([CSV::Row.new(%w{banana mango}, [1, 2])]).by_col.each'
 #=> /Users/sushant/.rbenv/versions/2.3.0/lib/ruby/2.3.0/csv.rb:850:in `block in each': undefined method `[]' for nil:NilClass (NoMethodError)
  from /Users/sushant/.rbenv/versions/2.3.0/lib/ruby/2.3.0/csv.rb:850:in `each'
  from /Users/sushant/.rbenv/versions/2.3.0/lib/ruby/2.3.0/csv.rb:850:in `each'
  from -e:1:in `<main>'

Ruby 2.4 fixed this issue.

Ruby 2.4

CSV::Row.new(%w(banana mango), [1,2]).each #=> #<Enumerator: #<CSV::Row "banana":1 "mango":2>:each>

CSV::Row.new(%w(banana mango), [1,2]).delete_if #=> #<Enumerator: #<CSV::Row "banana":1 "mango":2>:delete_if>

As we can see, these methods now return an enumerator when no block is given.

In Ruby 2.4 following code will not raise any exception.

> ruby -rcsv -e 'CSV::Table.new([CSV::Row.new(%w{banana mango}, [1, 2])]).by_col.each'