blueprint

BiggerPockets product & engineering blog

How we upgraded the BiggerPockets platform to Rails 7

The Ruby on Rails team recently released version 7 of their web application framework, and BiggerPockets has been on Rails since 2009, so we were eager to upgrade for a number of reasons. Despite our application being 237kloc, the upgrade was mostly done by one engineer, John Gallagher, with zero downtime and only a few post-upgrade bugs encountered. This post documents our lessons learned, but overall we could not be happier with how much easier it has become to maintain our “magestic monolith.”

Cached Queries

One big gotcha we ran into was only discovered in production. Part of our application was mistakenly architected to cache an ActiveRecord query (rather than just the results of the query). This led to a cryptic Arel error message for an undefined method.

This was fixed in two ways: 1) clear our application’s cache upon deploying Rails 7, and 2) rewrite any code that cached a query to actually cache the results of that query (there was only one instance of this):

- Rails.cache.fetch("key") { Model.scope.all }
+ Model.find(Rails.cache.fetch("key-ids") { Model.scope.ids })

Lesson learned: Avoid caching Rails objects. Rails query objects are incompatible between major Rails versions.

Changed behavior when combining attributes[] and ||

We ran into a really unexpected change with ActiveRecord’s []. The new logic makes more sense because it behaves like we’d expect from Ruby, definitely a head-scratcher as to why this worked before.

  def interest_only?
-   attributes["interest_only"] || true
+   attributes.fetch("interest_only", true)
  end

PDF rendering

We use the excellent Prawn gem to generate PDF documents for our customers. Rails 7 required that we define the format as an argument, rather than it being inferred from the partial’s file extension:

- WholesalingResultsController.new.render_to_string "show.pdf", locals: locals
+ WholesalingResultsController.new.render_to_string "show", locals: locals, formats: :pdf

Without this change, Rails just assumed that we wanted to render the Prawn template as HTML.

Sprockets

The legacy sprockets-based asset pipeline was removed from Rails. We still use sprockets, so we had to add it to our Gemfile:

# in Gemfile
gem "sprockets-rails"

Someday we hope to upgrade to a new asset manager. In the meantime, sprockets still gets the job done. We’re also using Yarn, so we had to add a yarn:install step to our Rakefile that compiles our assests (this used to be done automatically in Rails 6 and below):

# in lib/tasks/yarn.rake
Rake::Task["assets:precompile"].enhance ["yarn:install"]