How I run puma-dev alongside Rails’ bin/dev

The bin/dev script Ruby on Rails ships with, if you for example init the app with --css=tailwind or --css=bootstrap is great. It comes with auto-generated Procfile that will launch the web server and the Tailwind CSS (or other) preprocessors. In addition bin/dev will install the foreman gem if it does not exist on your system.

At some point however, you’ll want to run multiple Rails applications on your developer machine. Doing that with localhost:3000 will get annoying at some point (cookie sharing, changing ports, everyone in the team handling it differently, no HTTPS to test with…).

puma-dev has been around for a long time to solve this. However while it takes care of running the web server part for you (in the background), you still want to see the logs, run your CSS (or JS) preprocessor or compiler, job workers, etc. I figured out it’s simply about adjusting the Procfile and bin/dev slightly and one can use the familiar approach in conjunction with all the puma-dev features.

This is what I do:

My Procfile.dev looks like this:

web: tail -f log/development.log
css: bin/rails tailwindcss:watch

The change is in the web: stanza. Instead of launching puma server, we simply tail the logs, as puma will be run by puma-dev in the background for you, as soon as you visit your local .test domain.

My bin/dev looks like this:

#!/usr/bin/env bash

if ! command -v foreman &> /dev/null
then
  echo "Installing foreman..."
  gem install foreman
fi

if ! command -v puma-dev &> /dev/null
then
  echo "Installing puma-dev..."
  brew install puma/puma/puma-dev
  echo ""
  echo "To finish puma-dev setup run:"
  echo "sudo puma-dev -setup"
  echo "puma-dev -install"
  echo "puma-dev link -n myapp ."
  echo ""
fi

foreman start -f Procfile.dev

I’ve added a section that installs puma-dev (if your team is using Homebrew) and prints out instructions on how to complete the setup.

For your use case, simple replace “myapp” above with the name of your app.

This feels like sticking to the Rails way and is easily extensible if you also want to launch other services in development, like job workers, by simply adding a stanza in the Procfile.dev. Neat.

Scaffolding in Rails 7 is amazing

I’m continuously being impressed by the productivity and ease of use enhancements Rails keeps making after all these years it has been around.

Today I discovered that scaffolds generated in brand new --css=tailwind enabled Rails 7 codebase, is generating basic, beautiful Tailwind markup out of the box.

rails g scaffold_controller User username:string

Produces:

Index of a freshly generated model.
Edit view. Notice the Tailwind markup.

Further I have this in my config/application.rb to prevent generating files that I don’t use for every single resource until they are needed:

config.generators do |g|
  g.assets false
  g.helper false
  g.jbuilder false
end

That’s a damn good job Rails community. ❤️

Easily switch or experiment with different databases in Rails

I just learned about rake db:system:change task that Rails provides, to speed up switching between different database engines. If you’re experimenting with something, or benchmarking things, this is super useful.

I had a simple PostgreSQL app and running rake db:system:change --to=sqlite3 and afterwards rake db:setup got me going with my task in seconds.

Small detail I noticed, rake -T which should list all available tasks, does not show anything about db:system for some reason.

Starting new Rails applications

It’s been a while since I reviewed the documentation for rails new console command. There are a few useful features that I didn’t know about:

Most of the times, for database engine, PostgreSQL is my choice. This is easily accomplished with the -d switch, but even more convenient is adding this as a preset to your environment, using the .railsrc dotfile. Configuring such on your system will allow you to just stick to rails new appname without having to add switches.

The second useful thing I didn’t know exists is the Rails Application Templates which makes it faster to start new Rails applications with the same set of gems and configuration that you might be reusing across your apps.

Speeding up office work with Ruby and IRB

I was just paying taxes 😅. One of the steps involved was copying and pasting a few long reference numbers from a PDF into my banking app. The thing is, when copied, the reference number would contain extra spaces, after each character, making it invalid where I needed to paste it.

Now there are myriad of different solutions for this I’m sure, but as a programmer, let’s take a look at how to speedily create a makeshift tool in Ruby to do this.

irb
space_eater = ->(text) { text.gsub(' ', '') }

We launched into the interactive shell, and defined a lambda we can call on strings we want to sanitize. Like so:

space_eater.call('2 3 9 2 9 9 A 8 2 8 0 0 0 1')
=> "239299A8280001"

And we’re done. ❤️ Ruby.

Who is this feature for?

In software development, when thinking about and designing new features, or trying to solve existing issues, it’s important to, early, ask the question: Who is this feature for?

That applies to writing tools intended for your developer colleagues, web application features for customers or anything in between.

I found, that the result only tends to be good, if the feature or solution was actually designed for a specific person, doing specific task and this solution allows them to improve the way they do this task considerably.

For example when deciding for a Content Management System for a website, developers often jump to first evaluating various offerings out there, based on features, APIs and supported languages. Instead of first identifying the person that is going to be working with such a system and establishing what their workflow is going to be. What’s important for them, what’s not important and only based on that then look for a solution, or build a custom one.

Tools that are build for a very specific need and for a real person that can tell you, this helps, or not; tend to end up being simpler, more pleasurable to use, last longer and require less maintenance and generally tend to achieve the goal set out for them at the beginning.

Don’t forget about X-Forwarded-Host header

Recently I was working on a Rails application on Heroku living behind a reverse proxy. This application serves requests coming to a specific folder on the target domain. For it to correctly generate full URLs, you have to somehow tell this app the hostname you want it to use. In Rails, you can configure a hostname in the environment config file, but that’s a static value, which has to be maintained and changed per environment. Also it does not work well if you want to access the application from multiple domains.

It’s much better to be able to set something up on the proxy itself. For this reason the X-Forwarded-Host HTTP header exists. Rails–being a good web citizen–supports it out of the box.

Before I learned about this header, I even implemented my own middleware to deal with this issue and a custom header. I was able to dump that extra code once I stumbled at this header.

Web technology apps taking over?

It’s interesting to see that my 3 most used desktop apps, during my day to day computer use, are all web technology based:

  • Atom – My code/text editor.
  • Slack – Communication with my team.
  • Chrome – of course

The last time I was working on a desktop app, I used NW.js, which is a platform for building desktop apps using web technologies.

From my perspective, it’s no coincidence. HTML, CSS and JS are great tools for building lots of types of apps. I like this trend.

curl request and return headers only

The UNIX command line tools is something that just keeps giving. Within web development I often find myself wanting to quickly debug a URL, see whether it’s alive or what the response is. Often I do not want to download the whole content (a large file for example). Before I learned the following, I would use Chromes Developer Tools. That is until I learned how to do it more efficiently and quicker with good old curl:

curl -I https://klevo.sk

Which returns something like:

HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Sat, 27 Jun 2015 17:27:17 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive

It’s especially handy when setting up and testing temporary or permanent HTTP redirects. Doing that in a browser can be cumbersome due to caching.