Single file Rails applications - serving requests

Last time we packed a Rails application into a single file so that we can isolate bugs and easily share reproduction steps on GitHub or in a gist.

This time I wanna continue with the idea of crafting single files Rails applications that present an isolated topic by actually making them respond to requests. For that, we need to boot a webserver. Of course Rails has us covered here, since we can easily invoke rails server in our terminal, and Rails will boot our app and make it accessible via HTTP. We only need to find the right lines that make rails server work and invoke them in our app.

The first thing, however, we wanna do is to run our tests. Previously we’ve used minitest/autorun for this. Looking at the source code of Minitest.autorun reveals that it hooks into Ruby’s at_exit  callback. That’s not what we need, cause we obviously wanna run our tests first, and only then start the web server to serve requests.

Instead of requiring minitest/autorun, we’ll only require minitest and run our test suite manually:

exit_code = Minitest.run
exit exit_code unless exit_code

If tests pass, exit_code will be true. If tests fail, it will be false and we will exit.

Now let’s dig into the Rails source code to see how we can start our server. I did a simple search on rails/rails for “application starting in” and found server_command.rb. Let’s require the two command files and change Rails::Server.new code slightly, to pass it an options hash that specifies the app we wanna start and the host:

require "rails/command"
require "rails/commands/server/server_command"

options = {
 app: TestApp,
 Host: '0.0.0.0'
}
Rails::Server.new(options).start

When this is done, we can invoke our single-file Rails application via ruby rails_single_file.rb. It will first run our tests, and if those pass, start the rails server at port 3000. Now browsing to http://localhost:8080/primary_categories will show us the following text: “# of primary categories: 1” For the full sample, please see this gist.