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.