Announcing Shoulda Matchers 8.0: validate multiple attributes in one line

https://thoughtbot.com/blog/announcing-shoulda-matchers-8-0-validate-multiple-attributes-in-one-line

You know the drill if you’ve validated the same rule on a few attributes. One presence validation is one matcher, and five of them turn into five nearly identical lines that don’t tell the next reader much:

it { is_expected.to validate_presence_of(:first_name) }
it { is_expected.to validate_presence_of(:last_name) }
it { is_expected.to validate_presence_of(:email) }

Shoulda Matchers 8.0 is out on RubyGems, and it gets rid of that repetition. It also moves the gem onto Ruby 4 and the latest Rails. Let’s dig in.

One matcher, many attributes

Validation matchers now can receive more than one attribute, so those three lines become one:

it { is_expected.to validate_presence_of(:first_name, :last_name, :email) }

Qualifiers apply to all of them, so a grouped expectation reads just as clearly as the one-at-a-time version:

it { is_expected.to validate_presence_of(:arms, :legs).allow_nil }

Grouping doesn’t cost you anything when a spec goes red. The failure message calls out each attribute that failed and why, so you still land right on the problem.

These eleven matchers currently support the multiple-attribute syntax:

  • validate_presence_of
  • validate_absence_of
  • validate_acceptance_of
  • validate_confirmation_of
  • validate_length_of
  • validate_numericality_of
  • validate_inclusion_of
  • validate_exclusion_of
  • validate_comparison_of
  • have_readonly_attribute
  • have_one_attached

Ready for Ruby 4

8.0 runs on Ruby 4. We also bumped the supported versions up to the latest stable Ruby and Rails, so the gem matches the stack your app is probably already on and you won’t have to hold your test suite back to upgrade.

Keeping up with Rails associations

Rails is shifting to a new deprecated associations API. 8.0 supports it, so your association matchers keep working as Rails changes. Nothing for you to do here.

Upgrading

The only breaking change in 8.0 is dropping support for end-of-life Ruby and Rails versions, specifically Rails 7.1 and Ruby 3.2. If you’re already on a current Ruby and Rails, the upgrade should be seamless. Bump the version, run your suite, and you’re done. The new multiple-attribute syntax is opt-in, so your existing matchers keep working exactly as before. If you’re still on Rails 7.1 or Ruby 3.2, stick with the 7.x line until you can move up.

Thank you

Thanks to everyone who helped make this release happen.

Bump your Gemfile to 8.0.1 and let us know what you’d like grouped next. The full list of changes is in the CHANGELOG. Enjoy!

About thoughtbot

We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.