is used to speed up
the performance of queries
on a database.
allows us to create
index on a database column
by means of a migration.
the sort order
for the index
But consider the case
where we are fetching
reports from the database.
And while querying the database,
we always want to get
the latest report.
In this case,
it is efficient
to specify the sort order
for the index
to be descending.
specify the sort order
by adding an index
to the required column
by adding a migration
If our Rails application
is using postgres database,
after running the above migration
we can verify
that the sort order
was added in schema.rb
the index for name
has sort order in descending.
Since the default is ascending,
the sort order
for user_id is not specified
MySQL < 8.0.1
For MySQL < 8.0.1,
running the above migration,
the following schema.rb
As we can see,
although the migration runs successfully,
it ignores the sort order
the default ascending order is added.
Ruby has sequence predicates such as all?, none?, one? and any?
which take a block
by passing every element of the sequence to it.
Ruby 2.5 allows using a shorthand for this by
passing a pattern argument.
case equality operator(===) is used
against every element of the sequence
and the pattern argument.
This allows us to write concise and shorthand expressions where block
is only used for comparisons.
This feature is applicable to all?, none?, one? and any? methods.
Similarities with Enumerable#grep
This feature is based on how Enumerable#grep works.
grep returns an array
of every element in the sequence
for which the case equality operator(===)
by applying the pattern.
In this case,
the all? and friends return true or false.
There is a proposal to add it for select and reject as well.
While working on a client project, we started facing an issue where the JWPlayer stopped playing videos
we switched to hls
version of videos.
We found a CORS error in the JS console as shown below.
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 bucket will now allow requests originating from the specified hosts.
Cloudfront configuration changes
Cloudfront is a CDN service provided by AWS
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.
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
constraint in PodSpec to schedule pods on nodes.
We will use kops to provision
We can check the health of cluster using
$ kops validate cluster
Using cluster from kubectl context: test-k8s.nodes-staging.com
Validating cluster test-k8s.nodes-staging.com
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
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.
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.
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.
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.
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.
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:
With these changes along with
the official guide mentioned above,
our SP was able to authenticate users from multiple IDPs.
In this blog R stands for Ramda.js. More on this later.
Here is code without R.
Code with R.
Is the refactored code better ?
What is R?
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.
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.
we have been experimenting with composability.
wrote a blog
on how using
Recompose is making our React components more composable.
Let’s take a look at another examples.
We have a list of users with name and status.
We need to find all active users. Here is a version without R.
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.
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
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.
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.
In this way we can slowly start using functional concepts in our day to day
using Ramda.js today. Whether you are using React.js or Angular.js, it’s all