For Ruby developers,
it’s common to switch between
multiple Ruby versions for multiple projects
as per the needs of the project.
Sometimes, the process of
going back and forth with multiple Ruby versions
could be frustrating for the developer.
To avoid this we add
to our projects so that
version manager tools
such as rvm, rbenv etc.
can easily determine which Ruby version
should be used for that particular project.
One other case that Rails developers
have to take care of is ensuring that
the Ruby version used to run Rails
by the deployment tools
is the one that is desired.
In order to ensure that we
add ruby version to Gemfile.
This will help bundler install dependencies
scoped to the specified Ruby version.
Good News! Rails 5.2 makes our work easy.
In Rails 5.2,
changes have been made
to introduce .ruby-version file
and also add the Ruby version to Gemfile
by default after creating an app.
Let’s create a new project with Ruby 2.5 .
In our new project,
we should be able to see
.ruby-version in its root directory
and it will contain value 2.5.
Also, we should see following line
in the Gemfile.
In today’s era of containerization,
no matter what container we are using
we need an image to run the container.
Docker images are stored on container registries
like Docker hub(cloud),
Google Container Registry(GCR), AWS ECR, quay.io etc.
We can also self-host docker registry on any docker platform.
In this blog post, we will see
how to deploy docker registry
on kubernetes using storage driver S3.
We write scripts to automate setup and deployment of Rails applications.
In those scripts, at many places, we need to run system commands like
bundle install, rake db:create, rake db:migrate and many more.
Let’s suppose we need to run migrations using
rake db:migrate in a rails project setup script.
We can use Kernel#system method.
Executing system returns true or false.
Another feature of system is that it eats up the exceptions.
Let’s suppose our migrations can run successfully. In this case system command
for running migrations will return true.
Let’s suppose we have a migration which is trying to add a column to a table which
does not exist. In this case, system command for running migrations will return
As we can see, even when there is a failure in executing system commands, the return
value is false. Ruby does not raise an exception in those cases.
However, we can use raise explicitly to raise an exception and halt the setup
Ruby 2.6 make our lives easier by providing an option exception: true so that
we do not need to use raise explicitly to halt script execution.
Ruby 2.6 works the same way as previous ruby versions when used
without exception option or used with exception set as false.
Let’s see what happens when an exception is raised inside a thread.
Execution of it looks like this.
the last two lines from the block were not printed.
Also notice that after failing in the thread the program
continued to run in main thread. That’s why we got the
message “In the main thread”.
This is because the default behavior of Ruby is to
silently ignore exceptions in threads and then to
continue to execute in the main thread.
Enabling abort_on_exception to stop on failure
If we want an exception in a thread to stop further processing
both in the thread and in the main thread then we can enable
Thread[.#]abort_on_exception on that thread to achieve that.
Notice that in the below code we are using
As we can see once an exception was encountered in the thread
then processing stopped on both in the thread and in the main thread.
Thread.current.abort_on_exception = true
activates this behavior
the current thread.
If we want this behavior globally for all the
threads then we need to use
Thread.abort_on_exception = true.
Running program with debug flag to stop on failure
Let’s run the original code with
In this case the exception is printed in detail and
the code in main thread was not executed.
Usually when we execute a program with --debug option
then the behavior of the program does not change.
We expect the program to print more stuff but we do not
expect behavior to change. However in this case the --debug
option changes the behavior of the program.
Running program with join on thread to stop on failure
If a thread raises an exception
and abort_on_exception and $DEBUG flags are not set
that exception will be processed
at the time of joining of the thread.
Both Thread#join and Thread#value
will stop processing in the thread and in the main thread
once an exception is encountered.
Introduction of report_on_exception in Ruby 2.4
Almost 6 years ago,
Charles Nutter (headius)
had proposed that the exceptions raised in threads
should be automatically logged and reported, by default.
To make his point,
he explained issues similar to what we discussed above
about the Ruby’s behavior
of silently ignoring exceptions in threads.
is the relevant discussion on his proposal.
Following are some of the notable points discussed.
Enabling Thread[.#]abort_on_exception, by default,
is not always a good idea.
There should be a flag which, if enabled,
would print the thread-killing
In many cases, people spawn one-off threads which are not
hard-referenced using Thread#join or Thread#value.
Such threads gets garbage collected.
Should it report the thread-killing exception
at the time of garbage collection if such a flag is enabled?
Should it warn using
or redirect to STDERR device while reporting?
Charles Nutter suggested that
a configurable global flag Thread.report_on_exception
and instance-level flag Thread#report_on_exception
should be implemented having its default value as true.
When set to true,
it should report print exception
Matz and other core members approved that
Thread[.#]report_on_exception can be implemented
having its default value set to false.
Charles Nutter, Benoit Daloze and other people demanded that
it should be true by default so that programmers
can be aware of the silently disappearing threads
because of exceptions.
Shyouhei Urabe advised that
due to some technical challenges,
the default value should be set to false
so as this feature could land in Ruby.
Once this feature is in then the default value can be changed in a later release.
Let’s try enabling report_on_exception globally
It now reports the exceptions in all threads.
It prints that the Thread:0x007fb10f018200
was terminated with exception: divided by 0 (ZeroDivisionError).
Similarly, another thread Thread:0x007fb10f01aca8
was terminated with exception: undefined method '+' for nil:NilClass (NoMethodError).
Instead of enabling it globally for all threads,
we can enable it for a particular thread
using instance-level Thread#report_on_exception.
In the above case
we have enabled report_on_exception flag just for addition_thread.
Let’s execute it.
Notice how it didn’t report the exception
which killed thread division_thread.
As expected, it reported the exception
that killed thread addition_thread.
With the above changes
reports the exception as soon as it encounters.
However if these threads are
joined then they will still raise exception.
See how we were still be able
to handle the exception raised
in division_thread above after joining it
despite it reported it before
due to Thread#report_on_exception flag.
report_on_exception defaults to true in Ruby 2.5
Benoit Daloze (eregon)
strongly advocated that
both the Thread.report_on_exception and Thread#report_on_exception
should have default value as true.
is the relevant feature request.
We can disable the thread exception reporting
globally using Thread.report_on_exception = false
or for a
particular thread using Thread.current.report_on_exception = false.
In addition to this feature,
Charles Nutter also
that it will be good if there exists
a callback handler
which can accept
a block to be executed when a thread
dies due to an exception.
The callback handler can be at global level
or it can be for a specific thread.
In the absence of such handler libraries need to resort to custom
code to handle exceptions. Here is how
Sidekiq handles exceptions raised in threads.
Important thing to note is that report_on_exception does not change behavior of the code.
It does more reporting when a thread dies and when it comes to thread dies more reporting
is a good thing.
Ruby comes with
a simple standard library for test coverage measurement for a long time.
Before Ruby 2.5
Before Ruby 2.5,
we could measure just the line coverage using Coverage.
Line coverage tells us whether a line is executed or not.
If executed, then how many times that line was executed.
We have a file called score.rb.
Now create another file score_coverage.rb.
We used Coverage#start method
to measure the coverage of score.rb file.
Coverage#result returns the coverage result.
Let’s run it with Ruby 2.4.
Let’s look at the output.
Each value in the array [1, nil, 1, 0, nil, 1, nil]
denotes the count of line executions by the interpreter
for each line in score.rb file.
This array is also called the “line coverage”
of score.rb file.
A nil value in line coverage array means
coverage is disabled for that particular line number
or it is not a relevant line.
Lines like else, end and blank lines
have line coverage disabled.
Here’s how we can read above line coverage result.
Line number 1 (i.e. 0th index in the above result array) was executed once.
Coverage was disabled for line number 2 (i.e. index 1) as it is blank.
Line number 3 (i.e. index 2) was executed once.
Line number 4 did not execute.
Coverage was disabled for line number 5 as it contains only else clause.
Line number 6 was executed once.
Coverage was disabled for line number 7 as it contains just end keyword.
After Ruby 2.5
There was a pull request opened in 2014
to add method coverage and decision coverage metrics in Ruby.
It was rejected
by Yusuke Endoh
as he saw some issues with it
and mentioned that he was also working on a similar implementation.
Please note that column numbers start from 0
line numbers start from 1.
Let’s try to read above printed branch coverage result.
[:if, 0, 3, 0, 7, 3] reads that
starts at line 3 & column 0
ends at line 7 & column 3.
[:then, 1, 4, 2, 4, 15] reads that
starts at line 4 & column 2
ends at line 4 & column 15.
[:else, 2, 6, 2, 6, 15] reads that
starts at line 6 & column 2
ends at line 6 & column 15.
as per the branch coverage format,
we can see that
the branch from if to then was never executed
since COUNTER is 0.
The another branch from if to else was executed once
since COUNTER is 1.
Measuring method coverage helps us
identify which methods were invoked and which were not.
We have a file grade_calculator.rb.
To measure method coverage of above file,
let’s create grade_calculator_coverage.rb
by enabling methods option
on Converage#start method.
Let’s run it using Ruby 2.5.
The format of method coverage result is defined as shown below.
[Object, :grade, 9, 0, 17, 3] => 3
reads that the Object#grade method
which starts from line 9 & column 0
line 17 & column 3
was invoked 3 times.
We can measure all coverages at once also.
What’s the use of these different types of coverages anyway?
Well, one use case is to integrate this
in a test suite and to determine which
lines, branches and methods are executed and which ones are not executed
by the test.
we can sum up these
and evaluate total coverage of
a test suite.
Author of this feature, Yusuke Endoh (mame)
has released coverage-helpers gem
which allows further advanced manipulation and processing of
coverage results obtained using Coverage#result.
Stack trace or backtrace
is a sequential representation
of the stack of method calls
in a program which gets printed
when an exception is raised.
It is often used
to find out the exact location
in a program
from where the exception was raised.
Before Ruby 2.5
Before Ruby 2.5,
the printed backtrace contained
the exception class and the error message
at the top.
Next line contained where in the program
the exception was raised.
Next we got more lines
which contained cascaded method calls.
Consider a simple Ruby program.
Let’s execute it using Ruby 2.4.
In the printed backtrace above,
the first line shows the location,
error message and the exception class name;
whereas the subsequent lines shows
the caller method names and their locations.
Each line in the backtrace above
is often considered as a stack frame
placed on the call stack.
Most of the times,
a backtrace has so many lines that
it makes it very difficult
to fit the whole backtrace in the visible viewport
of the terminal.
Since the backtrace is printed in top to bottom order
the meaningful information
like error message,
and the exact location where the exception was raised
is displayed at top of the backtrace.
It means developers
often need to scroll to the top
in the terminal window
to find out what went wrong.
After Ruby 2.5
Over 4 years ago an
was created to make printing of backtrace
in reverse order configurable.
After much discussion
made the commit to
print backtrace and error message
in reverse order
only when the error output device (STDERR)
is a TTY (i.e. a terminal).
Message will not be printed in reverse order
if the original STDERR
is attached to something like a File object.
Typically our Rails app has services like unicorn/puma,
sidekiq/delayed-job/resque, Websockets and some dedicated API services.
We had one web service exposed to the world
using load balancer and it was working well.
But as the traffic increased it became necessary
to route traffic based on URLs/path.
However Kubernetes does not supports
this type of load balancing out of the box.
There is work in progress for alb-ingress-controller
to support this
but we could not rely on it for
production usage as it is still in alpha.
To have consistent and symmetrical behaviour
across all the attribute extensions,
it was decided to support specifying
a default value
using default option
for all the module and class attribute macros
mattr_accessor, mattr_reader and mattr_writer
generate getter and setter methods
at the module level.
cattr_accessor, cattr_reader, and cattr_writer
macros generate getter and setter methods
at the class level.
Before Rails 5.2
Before Rails 5.2,
this is how we would set the default values
for the module
and class attribute accessor macros.
After Rails 5.2
We can still set
a default value
of a module or class attribute accessor
by providing a block.
In this pull request,
support for specifying a default value
using a new default option
has been introduced.
So instead of
we can now easily write
to the other attribute accessor macros
like mattr_accessor, mattr_reader,
the old way
of specifying a default value
using the block syntax will work
but will not
be documented anywhere.
Also, note that if we try to set
the default value by both ways
i.e. by providing a block
as well as by specifying a
default option; the value
provided by default option
will always take the precedence.
would be set with true
as per the above precedence rule.
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.