Binary Solo
My name's Ayush. I'm a freelance web developer and I run Scattergun on the side. I'm also on the core team of the Bridgetown open source project.

I mainly write about web development using "boring" tech like Ruby on Rails, HTML and CSS; with the occasional musing about product design thrown in.

I'm on Twitter @ayushn21.

000001000001100001110000111






How I manage my git history
I'm generally a rather pedantic person and this is supercharged when it comes to managing the git history on my projects. I used GitHub's squash and merge for a while before Chris Moore taught me a few tricks.

I'm not a fan of squash and merge because it squashes an entire Pull Request into a single commit, no matter how large it is. This means that rather large changes could live under a single commit. I believe the commit history should tell a linear story, as pretentious as that might sound.



A clean commit history also makes life easier for…
Directing Turbo Native apps from the server
This post was extracted and adapted from The Rails and Hotwire Codex. It also assumes some familiarity with Turbo Native.

When developing for the web, we can send the user to any location during a web request using an HTTP redirect (3xx status codes). Turbo Native effectively wraps the website within native navigation. This means a redirect may not always do the trick.

Let's take an example. A Login screen is presented modally in the native apps. After a successful login, we want to redirect the user to the home page. In the app, we'd want to dismiss…
Turbo Streams meets Action Cable
This post was extracted and adapted from The Rails and Hotwire Codex.

Turbo Streams are a great match-up for Action Cable as it makes it easy to broadcast DOM updates to the browser over WebSockets. The turbo-railsgem integrates with Action Cable to facilitate such updates.

In this blog post, we'll look at how this integration works. Starting with code examples to establish a connection and broadcast Turbo Streams, we'll then dig into the individual client and server components of the integration.

An overview


turbo-rails contains a JavaScript custom element which encapsulates the logic to create an Action Cable…
Testing controller concerns in Rails
This post was extracted and adapted from The Rails and Hotwire Codex.

Concerns are a great way to organize and de-duplicate code in Rails. 

One of my favorite use cases is to abstract everything out of the ApplicationController into concerns. This begs the question: how do you test these concerns?

The approach for testing concerns is a bit of a judgement call as they're always mixed in with a class and aren't used on their own. Ideally we'd write tests to verify the behavior of a class which would also test the concern in the bargain.

But what if…
Rails system tests for multiple screen sizes
This post was extracted and adapted from The Rails and Hotwire Codex.

Rails system tests simulate a user's actions in a web browser so it's akin to the app's real world usage. In a responsive app, this means testing on multiple screen sizes as well.

Capybara, the tool used by system tests under the hood, has a method to resize the current window during a test run. But, since the tests are not run in a set order, any test that resizes the window needs to restore the size after it's done. Otherwise, subsequent tests run in that window…
Custom error pages in Rails
This post was extracted and adapted from The Rails and Hotwire Codex.

When something goes wrong in Rails, the user sees a rather boring default error page.

The default Rails 404 error page


This page lives in the /public folder and hence isn't rendered through the Rails stack. 

To jazz up this page a bit, we'll create a controller to render errors so the Rails infrastructure can be used.

Setting Up


A configuration change needs to be made so public facing errors are rendered in development rather than the exception and stack trace.

# config/environments/development.rb
require "active_support/core_ext/integer/time"
Rails.
Remote debugging in Rails 7
This post was extracted and adapted from The Rails and Hotwire Codex.

Rails 7 includes the official Ruby debugger. It also uses Foreman to orchestrate multiple processes in development. This way you can run the Rails server along with processes to watch and compile your frontend assets using a single command.

Annoyingly, this makes debugging trickier. You can't just add a breakpoint in your app and run commands in the console. The same Terminal window is running multiple processes, so won't always be interactive.

The debug gem supports remote debugging which is useful in such cases. Using this setup…
HTTP redirects in a Turbo-Rails app
This post was extracted and adapted from The Rails and Hotwire Codex.

In Rails, a conventional redirect in a controller action looks like:

def create
  # ...
  redirect_to root_path
end


This sends a response with an HTTP status code of 302 Found.
The Turbo docs, however, state that the response to a form submission must be 303 See Other unless something goes wrong.

The reason behind this is the spec for 302 Found states that the redirected request should use the same HTTP method as the original request. Due to legacy reasons, the fetch (used by Turbo under…
Add some spice to your HTML file fields with an image preview pane
The default HTML file field is rather boring. It's quite painful to style and not really flexible either.



With a little bit of JavaScript though, we can spice up the file input field a bit and add a preview pane for images; so the user can see the image they've selected before submitting the form.



A good way to encapsulate the logic for this field is to use a JavaScript Custom Element. We'll create a class called ImageInputField and define it to use the tag name image-input-field. Let's start with our HTML markup:

<image-input-field>
  <img preview>
  <input type=
Downloading data from Render.com's persistent Redis service
Render.com doesn't yet have a managed Redis offering, but we can still deploy a persistent Redis instance as a Private Service with an attached disk to store its data.

The problem is, Render's private services are not exposed to the internet, so how do we download the Redis data if we want to back it up, or migrate it somewhere else or whatever?

This Render article describes how we can get our hands on the data stored on attached disks using magic_wormhole. However, the Redis Docker image runs Alpine Linux; and to install magic_wormhole we need apt which isn't…
Deploy Rails and Sidekiq to Render.com using YAML
Render.com is a new Platform-as-a-service offering that's a great alternative to Heroku. Rather than think in terms of "apps" as Heroku does; Render has the concept of "services". So your Rails app would be a service; your database would be another service; Redis would be another service etc. Services could also potentially be shared between multiple apps.

Any non-trivial Rails app these days needs Background Jobs and a popular framework for this is Sidekiq. Sidekiq uses Redis as a data store. This means we need to deploy 4 services to Render to run our app:

  1. Rails web service
  2. Sidekiq background…
Namespacing keys in Kredis
Kredis is a library that provides an abstraction of higher level data structures for Redis. It's really useful and will be included in Rails 7.

I like to namespace all my keys in Redis because it prevents clashes between keys from multiple apps in development locally. It also opens the door to sharing a single Redis instance between multiple apps in production. That's usually not a good idea but for a few side projects, it might be a viable and economical choice.

At first glance it seems like it's really easy to add a namespace to keys in Kredis. There's…
How to generate YAML from Ruby objects without type annotations
Serialising a Ruby object to YAML is dead simple. Ruby's standard library has a yaml module built in which uses Psych under the hood. All we need to do is require 'yaml' and we're good to go! But there's a catch.

Let's say we have Photo and Album classes where an Album contains an array of Photos; and we want to serialise Album to YAML. This is what such a script would look like:
require 'yaml'
class Photo
  attr_reader :file
  def initialize(file)
    @file = file
  end
end
class Album
  attr_accessor :name, :photos

  def initialize(
Jazz up your hamburger menu icon
Hamburger icons are pretty ubiquitous these days but I sometimes find them to be a symptom of lazy design. However it's quite easy to make them a little more interesting!

In this blog post I'll explain how to build the below hamburger icon animation using only HTML and CSS.


Drawing the hamburger icon


We're not going to be using an SVG or anything so we need to "draw" the icon using HTML and CSS before animating it. We'll be using a checkbox to control the icon's state.

The markup for this component is very simple:

<input type="checkbox" id="hamburger-menu-checkbox"
How to circumvent importing Stimulus within every controller
If you're familiar with Stimulus at all, the below bog standard controller should look very familiar. In fact I've nicked it from their homepage!

import { Controller } from "stimulus"
export default class extends Controller {
  static targets = [ "name", "output" ]
  greet() {
    this.outputTarget.textContent =
      `Hello, ${this.nameTarget.value}!`
  }
}


I'm a Rubyist and unashamedly rather lazy; so having that import statement at the top of every Stimulus controller always irked me. If you're using Webpack, there's a super simple…
Maximum flexibility in Ruby method arguments with the splat operators
Ruby has got to be one of the most malleable programming languages out there, which is why I like it so much.

Recently I was adding breadcrumbs to a Rails app and wrote a drop_breadcrumb method that could be called in a controller or controller action.

I wanted the call site to look like:

class MyController < ApplicationController
  drop_breadcrumb "Home", :home_path, except: :index
  def show
    drop_breadcrumb "Profile"
  end
end

As demonstrated above, only the first argument is compulsory. So I need a method signature that accepts:
 
  • A single argument for the label
  • Two arguments for the label and…
Details & Summary tags: HTML's best kept secret
<details> and <summary> tags are among of the most useful tags that HTML gives us. I'm constantly surprised by how esoteric they are in practice.

In its simplest use case, the <details> tag gives us an "open/close" toggle control that shows the contents of the <summary> tag when closed; and all its contents when openend by clicking on it.


<details>
  <summary>Steven Wilson</summary>
  Steven John Wilson is an English musician, singer, songwriter and record producer. Currently a solo artist, he was the founder, guitarist, lead vocalist and songwriter of the band Porcupine Tree, as well as being a
Converting HTML to PDF using Rails
Exporting to PDF from HTML can be a bit of a can of worms, especially with CSS not quite working the way it does in a web browser. However with the right setup, it's possible to take the pain out of it!

A couple of popular gems to convert HTML to PDF in Rails are PDFKit and WickedPDF. They both use a command line utility called wkhtmltopdf under the hood; which uses WebKit to render a PDF from HTML.

I'd highly advise against using both those gems. They're good libraries but the underlying wkhtmltopdf doesn't support modern CSS features such…
Bridgetown's new webpack CLI tool
Bridgetown v0.21 includes a new CLI tool to manage Webpack so any improvements and updates to the Webpack config in later Bridgetown versions can be applied easily. 

# To view all available options
bundle exec bridgetown webpack
 
To avoid hiding a default webpack config in a gem or npm package; the config was split into two files: config/webpack.defaults.js and webpack.config.js.

webpack.defaults.js contains the base Webpack configuration provided by Bridgetown. webpack.config.js just requires webpack.defaults.js and re-exports it; allowing any user additions or overrides to be made before it's exported.

If you've already got a Bridgetown site, you can…
Applying monkey patches in Rails
Monkey patching is one of Ruby's most powerful features. It allows programmers to add methods to core classes which can result in some very elegant APIs. However it's quite easy to shoot yourself in the foot if you don't know what you're doing.

This post from Justin Weiss is a brilliant guide on how to monkey patch responsibly. However he doesn't describe how to actually include your monkey patches in a Rails app, so that's what I'm going to describe in this post.

Following Justin's advice, the implementation of all our monkey patches should go in the lib/core_extensions directory. So…
Ruby's quirky load order for mixins
Ruby modules are a great way to define mixins. This construct offers a way to share logic using composition.

As it is usually the case with Ruby, there's two ways of mixing (or includeing) ruby modules into your class:


class Post
  include Categorizable
  include Copyable
end
 
OR

 
class Post
  include Categorizable, Copyable
end
 
At first glance you might think those two syntax are identical, but Ruby has a quirk that isn't immediately obvious. To demonstrate this, let's print out a line from those two module when they're included:

 
module Categorizable
  def self.included(base)
    puts
How to submit an array using a Rails form
Sometimes an array of data needs to be submitted in an HTML form. A form to send invites to a bunch of users for example. That'd just be a series of email fields; and in the controller; we'd want an array of the emails to iterate over and send invites.

Rails form helpers are set up to have a key and value for each field, so it's not immediately obvious how to send an array of data. But in Rails, there's always a way!

If we append [] to the name of a field, it'll be parsed as an array…
Defining Rails application cron jobs in a rake task
rake has a variety of uses in Rails applications. You can use them to define and run installation and setup scripts, deployment scripts and pretty much anything you'd want to execute from the command line.

In Chapter24, I use a rake task that calls a Cloud66 HTTP endpoint to trigger a deploy.

namespace :chapter24 do
  task :deploy do
    key = Rails.application.credentials.cloud66[:deploy]
    exec "curl -X POST https://hooks.cloud66.com/stacks/redeploy/#{key} && echo \n"
  end
end
 
Additionally, I find they're also brilliant for defining cron jobs for your application. Instead of invoking…
A pjax powered HTML tab selector
pjax has got to be one of the most underrated programming techniques on the modern web. You can get a sizeable performance boost and dynamic page interactions by just dropping in a pjax library and not writing any JavaScript yourself.

Turbolinks and its recent successor Turbo Drive both leverage the pjax concept to allow multi-page apps to operate like single-page apps (SPAs) with little to no custom JavaScript.

The number of use cases in which you can use pjax instead of writing custom JavaScript is astounding. I recently revamped my portfolio website. As part of the revamp, I wanted to…
Toast notifications using a JavaScript custom element
Toast notifications are a great way to give the user ephemeral, unobtrusive feedback about an action they have just carried out.

Twitter uses them in response to a lot of actions such as posting a new tweet or deleting a tweet. HEY also uses them to confirm email categorisation actions among other things.




A plethora of applications (including my app, Chapter24!) use Toasts in a variety of ways and these are just a couple of examples I could recall off the top of my head. In…
How I organise my project-specific plugin code in Bridgetown
As I covered in my last post, Bridgetown is a new static site generator that's been forked from Jekyll. It includes Webpack as a first class citizen so it's all set up to allow developers to build modern front ends without any extra configuration.

For most simple websites, you're unlikely to need any custom Ruby code as Bridgetown packs in quite a bit of functionality out of the box; but for anything non-trivial; it's very likely you'll have to extend Bridgetown with plugins.

In my last project, I wanted to showcase some of my photography along with the technical data…
A static HTML website starter template using Bridgetown
Static HTML websites are incredibly popular these days. They're unparalleled in performance as you can serve them via CDNs which are blazing fast. Also they're incredibly easy to deploy thanks to services like Netlify.

To build static websites with changeable content and without repeating code requires the use of a static site generator.

There's quite a few popular generators; but being a Rubyist, I've used Jekyll for a number of websites. While it's awesome; I thought it was a bit out of date as it does not integrate Webpack by default. Anyone who's looked at a webpack.config.js knows that hitting…
The usefulness of Wheaton's Law in product design
Software product design these days is becoming more and more driven by metrics. A side effect of that is products are becoming largely homogenous. The recent release of Fleet by Twitter is a case in point. Companies are focused on making some graph or other go higher and higher instead of building cohesive and engaging user experiences.

This obsession with metrics often leads to experiences that are egregiously user hostile. Wheaton's Law is an implicit or explicit prerequisite for working at most software companies; however very few seem to apply it to their product design as well.

In this post…
Demystifying cookies in Rails 6
Cookies are used in pretty much every modern web application. They're used for various purposes such as facilitating user authentication and storing user preferences. Since they're so widely used it's no surprise that a full-stack development framework like Rails has a simple and convenient API to manage them.

In this post I'll describe the different types of cookies supported by Ruby on Rails and how they work under the hood.


Types of Cookies in Rails


Rails supports the storage of 3 kinds of cookies:

  • Plain text: These cookies can be viewed and changed by a user.

  • Signed: Signed…
How Chapter24 works under the hood
Chapter24 is a super simple to use blogging platform. I built it and am running myself without any collaborators. That meant I needed a tech stack and architecture that made it quick to build and easy to run as a solo endeavour.

Tech stack and high level architecture


At its core, Chapter24 is a Ruby on Rails monolith that runs on a single $5/month DigitalOcean box. In keeping with the Rails philosophy, I'm using server side HTML rendering with Turbolinks and Stimulus on the front end. I've got Sidekiq for running background jobs and my database is a DigitalOcean managed…
Web designers, please stop punching your users in the face
Modern web design has many flaws; however it's truly mind boggling how many websites are positively user hostile with subscription popups.

It happens way too often; I load a web page or I'm scrolling down one and I get a punch in a face with a modal that says "SUBSCRIBE TO ME! I DEMAND YOUR EMAIL ADDRESS!". I have literally no idea how or why this technique even works (assuming it does work); especially when the copy is passive aggressive. All it makes me want to do is close the window.

Why a developer or designer would want…
Avoiding session replay attacks in Rails
There are a lot of good reasons to roll your own authentication rather than use something off the shelf like Devise. This comes with its own pitfalls and a rather easy mistake to make is to leave a vulnerability for session replay attacks by solely using the "user id" as an authentication instrument. 

In this post I'll describe how such an attack can be carried out; why it's so serious and how to protect your app against it. 


A typical login mechanism


A common pattern for Rails authentication is to have a SessionsController with a create action for login and…

Subscribe to Binary Solo


We'll send you an email every time a new post is published. We'll never spam you or sell your email address to third parties. Check out our privacy policy for details.