---
title: A new version of Suspenders has been released!
teaser: We took our Suspenders to the tailor and made some alterations.
tags: rails,suspenders,open source
author: Steve Polito
published_on: 2024-05-20
---

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.

[Suspenders]: https://github.com/thoughtbot/suspenders
[alterations]: https://github.com/thoughtbot/suspenders/releases/tag/v20240516.0

## 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
```

[dotfiles]: https://github.com/thoughtbot/dotfiles
[railsrc]: https://github.com/rails/rails/blob/7f7f9df8641e35a076fe26bd097f6a1b22cb4e2d/railties/lib/rails/generators/rails/app/USAGE#L5C1-L7

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

```ruby
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][a11y 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][pr description].

[application template]: https://guides.rubyonrails.org/rails_application_templates.html
[capybara\_accessibility\_audit]: https://github.com/thoughtbot/capybara_accessibility_audit
[a11y violations]: https://www.w3.org/WAI/standards-guidelines/wcag/
[pr description]: https://github.com/thoughtbot/suspenders/pull/1135#issue-1946314236

## 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.

[feature set]: https://github.com/thoughtbot/suspenders/blob/f9a702aad4d9006c5f4b03fd29557dbcf96a6b51/FEATURES.md
[goals]: https://github.com/thoughtbot/suspenders/blob/main/GOALS.md
[generators]: https://guides.rubyonrails.org/generators.html

## 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][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][testing discussion]) 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][engine 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.

[first release]: https://thoughtbot.com/blog/suspenders
[Rails::Generators::AppGenerator]: https://github.com/rails/rails/blob/main/railties/lib/rails/generators/rails/app/app_generator.rb
[engine]: https://guides.rubyonrails.org/engines.html
[example]: https://github.com/rails/rails/pull/51191
[engine testing]: https://guides.rubyonrails.org/engines.html#testing-an-engine
[Rails::Generators::Testing::Assertions]: https://api.rubyonrails.org/classes/Rails/Generators/Testing/Assertions.html
[Rails::Generators::Testing::Behavior]: https://api.rubyonrails.org/classes/Rails/Generators/Testing/Behavior.html
[testing discussion]: https://github.com/thoughtbot/suspenders/pull/1156#issuecomment-1912168496

## 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][integration] with [Flightdeck][] as
we continue to do more [work on AWS][aws].

[Rails 8]: https://github.com/rails/rails/issues?q=is%3Aopen+is%3Aissue+milestone%3A8.0.0
[integration]: https://github.com/thoughtbot/suspenders/issues/1189
[Flightdeck]: https://github.com/thoughtbot/flightdeck/
[aws]: https://thoughtbot.com/devops-sre-cloud-platform
