A new version of Suspenders has been released!

Steve Polito

We took our Suspenders to the tailor and made some alterations. If you just want to see what changed, you can view the new feature set. Otherwise, continue reading to learn more.

What changed?

In an effort to achieve our goals, we removed the suspenders system executable and replaced it with an application template that invokes a set of generators.

So, instead of running suspenders app_name, you would now run the following:

rails new app_name \
 --skip-test \
 -d=postgresql \
 -m=https://raw.githubusercontent.com/thoughtbot/suspenders/main/lib/install/web.rb

Alternatively, if you’re using our dotfiles, then you can just run rails new app_name, or create your own railsrc file with the following configuration:

--skip-test
--database=postgresql
-m=https://raw.githubusercontent.com/thoughtbot/suspenders/main/lib/install/web.rb

Additionally, you can now use Suspenders on existing Rails 7 applications simply by adding the gem like so:

group :development, :test do
  gem "suspenders"
end

From there you can either run suspenders:install:web to invoke all the generators, or you can invoke generators individually. For example, you can run suspenders:accessibility to install capybara_accessibility_audit, which automatically audits pages for WCAG Standards-based accessibility violations.

In addition to the implementation changes, we also audited the existing behavior. We removed configurations that were either obsolete, or no longer reflected our current opinions. You can get a sense of how involved the auditing process was by looking at the pull request description.

Why the change?

Over time, Suspenders became difficult to contribute to, and therefore difficult to maintain. The biggest barrier to entry was the slow test suite, which clocked in at around 13 minutes. Because of this, it became stagnant and no longer represented our latest opinions.

Here’s a quote pulled directly from our goals.

The problem with a script that adds a bunch of gem requirements to the Gemfile is: what if you don’t want all those gems? Suspenders adds gem requirements and then configures each one. On a typical project we would run Suspenders then spend the rest of the day un-doing the parts we don’t want.

To address this, we knew the rewrite needed to be lean and rely on rails new as much as possible, deviating only when necessary. This is reflected in the new feature set, which is relatively concise.

By removing what we didn’t need, and relying only on generators, we were able to cut our testing time down from 13 minutes to only 2 minutes. With this in mind, our hope is that others within the organization will feel empowered to contribute to Suspenders.

How did we make the change?

Suspenders is old. The first release was in 2008. The current implementation is a hybrid of generators and a wrapper around Rails::Generators::AppGenerator. This makes sifting through the current implementation and tests cumbersome. Not only that, but much of the generated code was rendered obsolete over the years as Rails has matured. Because of this, we took the bold (yet refreshing) approach of replacing the existing project with a freshly generated Rails Engine.

This allowed us to audit the current build in isolation, and pull in new and modified generators one-by-one. A pull request was made for each generator, which allowed for easier review and discussion (like whether we should move off of RSpec) before it was merged into the long-runner suspenders-3-0-0 feature branch. The idea was that we’d build Suspenders back up, one generator at a time.

Using an Engine also provided us with an excellent testing foundation, thanks to Rails::Generators::Testing::Assertions and Rails::Generators::Testing::Behavior. This alleviated us from having to create a bespoke test harness, and allowed us to focus on building our generators.

We also took this opportunity to upstream what we could into Rails. The idea being that if a feature exists in Rails, it’s one less thing we need to maintain. Not to mention it would have more reach being in Rails than in Suspenders. One noteworthy example is a developer experience improvement affecting how mailers are configured in test and development environments.

What’s Next

We’ll be keeping an eye on Rails 8 in an effort to ensure we continue to strike a balance between new Rails defaults and our opinions. Additionally, we also want to explore a better integration with Flightdeck as we continue to do more work on AWS.