How to create a single-file Ruby app
Ruby-on-Rails generates a lot of artifacts when you start a new application. Just typing rails new app_name gets you started quickly. It's an opinionated way to implement a web application. The good thing is that any Rails developer generally knows where to look for things. For example, I know that images are going to be located in the app/assets/images directory.
However, in a lot of cases, you actually don't need many of the generated artifacts. If you take a look at the app directory structure, there's a vendor directory, a storage directory, and other nested directories you likely may not use.
Thanks to some pioneering work by Nate Berkopec on lightweight rail Stacks, we can pare down the rails application to the absolute bare minimum and make it a lot simpler. Take a look in your rails application directory and you’ll see a file you probably haven't paid much attention to, config.ru.
The config.ru file really just runs your Rails application. The extension is short for rack up. Here is the default version that came with my app.
So what is Rack? Rack sits between your Rails application and your web server, puma in my case. It provides an abstraction that allows you to swap out the web server if you like. It performs quite a bit of request handling logic.
To see what it's actually doing, run the rake middleware command. This command will take a moment to run, but it will list all of the different handlers that every request to your application goes through. This includes things like logging, exception handling, and session management. There is a lot of good stuff in there which fortunately, you generally don’t have to think about.
Now, if you are thinking that the config.ru file appears to be the equivalent of a Java main function, you are correct. It gets your Rails app started and pulls in artifacts from your config directory, for example environment specific information and secrets. It starts your web server process and wires up routing to your controllers.
Simplifying our App
We are building an instant poll application that we can embed into a larger page. We want the code to be as compact as possible. The end result looks like this.
The primary components are shown in the diagram, however our goal will be to condense all of this into the config.ru file.
For our purposes here, we store the poll results in memory as opposed to a database. That allows us to get rid of our model classes. As for the view component, we don't have to separate that into its own file. We do lose the ERB templating feature, but we can render HTML directly from the controller.
The controller class definition moves to the config.ru file, and we inline only the necessary configuration elements. We are down to one file now! Here is the start where we extend the Rails application and we set only the absolute required configuration elements. There is only a single URL which handles the initial GET and the form POST. We need to set the X-Frame-Options header to allow our application to be embedded into other web pages.
Our inline controller looks to see essentially if this is the view of the pool or a submission. On a submission, it keeps track of the counts and renders the results in HTML Otherwise the form itself is displayed. We have 76 lines of code, with most of it actually being the HTML.
At the very end, you have the app initialize and run statements that you would find in a typical default version of this file. Finally, we run our app using the command bundle exec puma -p 3000
After a few submissions, the results look like this.
This is a pattern you can use to implement embedded apps or microservices. We built our instant pool app in 76 lines of code on Rails 5.2. Aside from the HTML stuffed into the controller class, it's actually somewhat elegant. The complete code for the Instant Poll app can found here,
Hope you found this useful and let us know what micro-applications you are able to build on Rails.