A simple Rails development environment using nix-shell
This nix-shell environment provides a Ruby environment capable of running a Rails app without a database
This follows on from my previous article about setting up a simple Ruby development environment using nix-shell. The next thing I wanted to try was to set up a simple Rails development environment. To this end I decided to focus on the GFR website which is a Rails app, but has the advantage that it doesn't use a database.
The Gemfile
for this project specified Ruby v2.5.7 and so as before, I upgraded it to use the latest v2.5 patch version, v2.5.8, so that I could use the ruby_2_5 package provided by nix.
In a similar vein, the Gemfile.lock
was BUNDLED WITH
v1.17.3 of bundler; whereas the bundler version provided by nixpkgs was v2.1.4. The line in Gemfile.lock
wasn't an enforced constraint and I didn't want to break our Heroku deployment, so I compromised and upgraded to the v2 version of bundler supported by the Heroku Ruby buildpack, i.e. v2.0.2.
My shell.nix
ended up like this:
with (import <nixpkgs> {});
let
env = bundlerEnv {
name = "site-bundler-env";
ruby = ruby_2_5;
gemdir = ./.;
};
in mkShell {
buildInputs = [ env env.wrappedRuby ];
}
The full set of changes including the gemset.nix
generated by bundix are in this commit.
At this point I was surprised to discover that I could run rails server
from within my nix-shell
and everything worked perfectly! π
$ nix-shell
# ...
$ rails s
=> Booting Puma
=> Rails 5.2.4.3 application starting in development
=> Run `rails server -h` for more startup options
# ...
Started GET "/" for ::1 at 2020-09-10 18:05:37 +0100
Processing by PagesController#show as HTML
# ...
Completed 200 OK in 170ms (Views: 23.9ms)
Observations
It's worth noting that early on in the shenanigans above, I got stuck for a while with the wrong version of Ruby and nothing I did would change it. In the end I deleted a bunch of things in my /nix/store
directory to fix the problem. While this probably wasn't the right way to fix it, I really appreciated the way it's relatively easy to work out how various executables are being made available to your environment, i.e. via a series of symbolic links.
I also worked out that it's not possible (at least not when using bundlerEnv
) to specify the version of bundler you want to use - it seems to be fixed at v2.1.4.
Next steps
I'm still interested in working out how to have a project use a specific patch version of Ruby and to be able to lockdown the exact version of bundler. I've been reading about nix flakes and although I haven't completely got my head around them, I think they might be what I'm looking for, because they have a "lock file" which I believe can pin your dependencies to ensure reproducibility.
However, I still feel as if that's a bit of a tangent. My main aim is to be able to have multiple Rails projects on the same computer with various flavours and versions of databases, etc. So I think my next step should be to setup a development environment for a Rails project which uses a database.
Update: I've belatedly realised that some run-time dependencies (e.g. node.js & yarn) were satisfied by OS packages installed in my OSX environment, i.e. I forgot to isolate the nix shell from this environment like I did when investigating the dependency on node.js in my previous article. I plan to tackle doing this soon.
Further reading
If you'd like to know more about nix flakes, I can recommend these articles by Eelco Dolstra: