Blog

Thoughts from my daily grind

Ruby on Rails in Vagrant - Code Not Reloading

Posted by Ziyan Junaideen |Published: 10 March 2021 |Category: Code
Default Upload |

I work on both Ubuntu Linux on my laptop and MacOS Catalina on my iMac for client projects. When I am on Linux, I run projects natively on the machine without using any virtualisation. When I am on Mac, I use Vagrant - Virtual Box and Chef Solo combination to quickly provision development environments identical to their respective production environments because I want to avoid "Works on my machine" issues.

About 2 weeks ago I started a new Ruby on Rails (Version 6) project. I bought the theme moved the HTML, CSS and JavaScript. While working on Webpacker and the theme JS I noticed that the code was not getting recompiled when refreshing. Stopping and doing rails s seem to work. That is when I realised that file changes were not getting propagated.

The Problem

For Rails to reload your code changes, it needs to know when it changes. Operating systems provide neat feature where applications can listen to file change events. This is the case in Rails 6. The problem was that I changing the files in MacOS in my iMac and Ruby on Rails running inside a Vagrant Ubuntu 20.04 virtual machine. There is a disconnect where the mounted folder related file system notifications are not relayed to the guest machine.

Since this is a new issue I knew there had to be another way. That is "polling". I tried to use polling but I don't think I had luck with it.

The Solution

If the problem is not receiving notifications of file changes, the solution would be to monitor file notifications on the host and inside the guest to mark the file as updated. touch command does just that.

Fortunately some body had already done that and come up with the plugin vagrant-fsnotify.

It listens to file system changes and then relays a touch command so that Rails in the guest knows a file changed.

Installation & Configuration

Installation of the plugin is easy. It took unusually long but I think the server serving the files were slow.

=> vagrant plugin install vagrant-fsnotify

Then in your Vagrantfile you can add this to the bottom of the file.

Vagrant.configure("2") do |config|
  # ...

  config.vm.synced_folder ".", "/vagrant", fsnotify: true, exclude: %w[*.git/ *.tmp/ *cache/ *log/ *node_modules/]

  config.trigger.after :up do |t|
    t.name = "vagrant-fsnotify"
    t.run = { inline: "vagrant fsnotify" }
  end
end

So basically I am configuring the synced folder - current working directory to the /vagrant folder in the guest with fsnotify: true. then I am excluding some paths. Namely .git/, .tmp/, cache/, log/ and node_modules/.

I first started without the excludes. I have a Core i9 and it can pull weight. But soon I noticed there was a problem. The fan that rarely comes was running full steam. On inspection I noticed there was a Ruby thread using a lot of CPU. The issue seemed to be related primarily to changes in the .git folder. I didn't take chances. I excluded every thing I don't mind excluded.

Conclusion

fsnotify is a must use plugin if you are working on a Vagrant powered development environment. I can't imagine how cumbersome life would be if I had to restart the app after every little change. That couple hours until I figured out fsnotify was a nightmare. Happy hacking!

Tags
About the Author

Ziyan Junaideen -

Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.

Comments