Setup Windows 10 to run Ruby on Rails using the new & improved WSL

Is it possible to develop Ruby on Rails applications with Windows? Develop applications that are production ready and made by teams running around with Windows machines instead of Macs? Most will think it is unlikely and not without reason. David Heinemeier Hansson introduced Rails as tools to counter Microsoft’s influence. In line with his ideals, Ruby on Rails has not received much attention on Windows systems. But Microsoft has changed and with it Windows and DHH’s opinion of Microsoft. 2016 saw the inclusion of bash in Windows and with the recent improvements it is possible to foresee Windows becoming great for Rails development.

But is it ready now?

I moved to MacOS after joining FiNC and it has been a great experience. Simply put I love the MacBook. I even encouraged my wife to also buy one (pink of course!). However, the real reason for my shift was Window’s poor gem support that made work a challenge at times. So it was not ready before. If it is ready now, it would be great to have more choice and perhaps I could move to an impressive MSI’s light-weight gaming laptop.

An alternative to directly developing in Windows is using Linux on a virtual machine. However, maintaining Linux on virtual machine counts as doing ‘too many things’ for me. Ideally I would like to have a simple and fully functional development environment.

So I tried to install Ruby on Rails using WSL (Windows Subsystem for Linux), the Bash that comes built-in with Windows 10. After a few steps, it can be setup to run Ubuntu. But even these steps will become unnecessary as Microsoft is offering Ubuntu, Fedora and Suse on its store. These do not appear to be available for direct download yet on Microsoft Store and articles that reported it did not provide a link. However, from command line with admin rights, one can easily install Ubuntu from Microsoft Store with a single command.

One might shrug off WSL as a ‘feeble attempt to mimic cygwin’. But it couldn’t be more wrong and right! Ubuntu’s parent company has helped Microsoft with recompilation of cygwin’s libraries. So now Windows can do a live/real-time translation of linux OS/subsystem calls to its kernel without any virtualization or emulation. This is the closest one can get to the real thing and I plan on testing it.

WSL has recently got a major update and more are expected to follow. I want to see if all the gems used in my company’s web application will run or not. I also want to test the comparative performance of the two systems. I often hear this argument of apples vs oranges but the simple fact is that my macBook was quite costly and a respectable gaming laptop can cost significantly less.

I use the official guide on Ruby on Rails website to setup my system. It describes how to setup Bash to run Ubuntu and then how to install Rails.

My first attempt to install Ruby v2.4 did not go very well (using rbenv). After setting up rbenv, I ran the install command:

rbenv install 2.4.0

But this apparently got stuck or was taking too long. I canceled the command but this lead to problems later. So now I am updating to Windows 10 Creator’s update. This includes many updates to WSL. I think the most important changes are improved compatibility with Linux System Calls and File Change Notification (INOTIFY) support. A summary of the features are listed in zdnet’s article.

Next I fully remove and reinstall WSL with the following commands on CMD:

# Uninstall completely:
lxrun /uninstall /full /y
# New install (root user created):
lxrun /install /y

This worked perfectly and I had a clean version of Ubuntu running. I checked the version and found it to be latest long term support release (16.04.2).

root@DESKTOP-A81EGOK:~# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.2 LTS
Release: 16.04
Codename: xenial

Now I followed the steps in the official rails guide to install ruby and rails:

sudo apt-get update

First I install some necessary dependencies (takes about 9 minutes).

sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev

Some other dependencies could be optionally installed (qt5 if capybara is used and imagemagick if rmagick is used)

sudo apt-get install qt5-default libqt5webkit5-dev gstreamer1.0-plugins-base gstreamer1.0-tools gstreamer1.0-x
sudo apt-get install imagemagick libmagickwand-dev

Next I use RVM to install ruby (takes about 8 minutes). Rails guide recommended rbenv but it didn’t work for me last time. So I preferred to use ruby version manager (rvm) this time around.

sudo apt-get install libgdbm-dev libncurses5-dev automake libtool bison libffi-dev
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm
rvm install 2.3.3
rvm use 2.3.3 --default
ruby -v

NOTE: I had to replace ‘source ~/.rvm/scripts/rvm’ with ‘source /etc/profile.d/rvm.sh’. Please keep an eye on the messages reported.

NOTE (2): Unfortunately I first tried rvm install 2.4.0 but that caused problems, so I have to revert to an earlier version.

NOTE (3): After installing everything and closing bash, I appeared to have lost the installed packages when I opened bash again. But the only issue was that RVM had to be re-sourced.

Next I installed bundler gem:

gem install bundler

I skipped the section on GIT setup and went directly to installing rails:

root@DESKTOP-A81EGOK:~# ruby -v
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
sudo apt-get install -y nodejs
gem install rails -v 4.2.7.1

The whole process took 24 minutes. Installing Nokogiri gem and ‘ri documentation for rails’ both took about 8 minutes.

root@DESKTOP-A81EGOK:~# rails -v
Expected string default value for ‘ — rc’; got false (boolean)
Rails 4.2.7.1

I skipped installing MySQL for ubuntu and directly installed MySQL for Windows using the downloader available from msql site. The whole process took about 6 minutes.

I still needed to install sqlclient library in bash using:

apt-get install libmysqlclient-dev

And to check if SQL is accessible within bash, I also installed the MySQL client. I used it to connect to the database using IP address of localhost as a host:

apt install mysql-client-core-5.7
mysql — host=127.0.0.1 — user=root –p

Now I make a new directory and create a new rails app inside it. When doing pico/vim on database.yml, be sure to set host as 127.0.0.1

> mkdir test
> cd test
> rails new myapp -d mysql
> cd myapp
> pico config/database.yml
> rake db:create

Another option could be to add a variable to .bashrc. Some people do not recommend this as it can cause unexpected behavior when we do our individual project settings. I did not test it myself, but it would work out as:

export MYSQL_HOST=tcp://127.0.0.1

On running ‘rails s’ in bash, I can go to Edge browser and put the address “localhost:3000” to get the following page:

Voila! We are able to run the rails server in bash and access it directly in Windows. But wait…What have we achieved that could not have been achieved by setting up rails directly in Windows? As we know, Rails can be configured to run in Windows. One tool that is helpful is railsinstaller and a decent guide on installing rails for Windows is from treehouse.

However, I hope to achieve two things with such configuration:

  1. Support all those gems that are not supported out of box for Window so that complex applications can be configured easily
  2. And get a boost in performance compared with running rails on a virtual machine.

So now I will try to run one of FiNC’s web application on rails. Will it run? Here we find out. I download the web application from github (without running command line). Then I go to the directory where the web application is saved. Say I had saved the web application in F:/FiNC/Saad/our_special_app. Now I go to this folder in bash with the following command

cd /mnt/f/FiNC/Saad/our_special_app

I would need to run ‘bundle install’ in the application directory and run the rails server. My first attempt failed because Capybara webkit related tests were failing. I ended up including headless gem (with related setup in rails_helper.rb) and installing xvbf. More information is available in both Capybara webkit and the headless gem home page. I also got useful information from this stackflow question.

Finally, I have my gems installed and my application ready. I run rails server and get the following page in my localhost:

Whoopee! What we could not configure directly in Windows before can now be run in Windows with a little help from bash.

I am still not done yet as I would like to ask myself if there is any performance gains in there and if WSL is as good as Microsoft claims it to be.

For this I run the tests on FiNC’s mall shopping application by checking the time to completely load the main page and the time to run all the tests. This is a big application and takes some time to do a bundle install. The interesting thing is that on my MacBook I ran into problems so could not do it in a single go.

First the performance on my MacBook: the first page loads in about 29s while the tests take about 20min 43s (total of 1965 examples). The slowest tests are shown in the chart below compared with WSL on Windows.

Slowest tests with time in seconds (lower is better)

Running the similar suite of tests on my Windows machine, I can get through the tests in 35 minutes for 1955 tests. While the total time is more, the slowest tests hint of only slight performance difference.

The second test was first page load. First page took about 130s on my first run and next time took about 68s. However, the page itself loaded within 20s and was trying to load images it could not find.

I should point out that a comprehensive test should include statistical analysis and worst/best cases which I have not done (repeated results varied wildly). I took results that were fairly good representative of each system’s performance.

Summary of the performance comparison:

  1. CPU relative performance: 1.5x — 1.9x faster CPU in MacBook (but usually cannot sustain higher frequencies due to heat)
  2. Spec tests: MacBook is about 1.75x faster
  3. First page load with all resources: MacBook is about 2x faster
  4. First page load without images load: Similar
CPU usage
Data transfer

While doing performance monitoring, I was pleased to see that ruby was recognized as a separate service. But I was concerned that it was taking only 20% of CPU which eventually went down further to 11%. As a single thread, it should have been using 25%-50% on my quad-core machine. It seems that there is a bottleneck somewhere. Perhaps it was the SSD on my Windows machine, as it is slower and there were noticeable peaks on read. A more likely reason is missing optimization for services run in WSL. That would explain why rails on WSL uses less memory than rails on MacOS. Windows reported 700 MB between rails and mysql with ~100MB for various services, while macBook reported about 1.1Gb (spread over 4 services related to ruby). I would not be surprised if Apple has optimized its OS to use all memory resources to improve performance.

Of course my Window’s hardware could be faster as it can be actively cooled. But the main advantage is I have 16 GB ram in my Windows machine while my MacBook has to do with only 8 GB. It means I could effectively run more than 1 instance of rails on WSL unlike my MacBook which has great difficulty handling 2 instances of rails server. Multiple WSL instances are not supported out of the box but can be setup using tools like ConEmu.

There are some caveats though:

  1. Rails related tasks feel a little ‘delayed’ in starting up with WSL.
  2. Capybara webkit tests failed initially and I had to do a little extra setup with headless and xvfb.
  3. I got a D-Bus library error. The fix was easy enough but it initially slowed the tests.
  4. Performance results vary wildly.
  5. High CPU usage but actual services (ruby/mysql) were using small percent of it
  6. WSL does not like linux files being tampered in Windows. In extreme cases, the bash itself may get corrupted.

Despite all these issues, WSL looks great! It only falls a little short in terms of performance. But it is ready and usable today. It handled our large web store code without failing. I would go so far as to say that the setup was a better experience than I had on my MacBook. My impression is that by the time it comes out of beta, it should easily facilitate most demanding IT professionals and developers. Using Windows as a development machine is now a matter of preference rather than limitations of the system.

Additional References

WSL recent announcement summary

Path of WSL in Windows and reinstalling the subsystem

Docker web application using WSL

How to connect from bash (WSL) to MySQL

Why using Ruby 2.4~ is not a good idea